3

假设我们有一个如下表,

+----+---------+--------+
| id | Name    | Bunnies|
+----+---------+--------+
|  1 | England |   1000 |
|  2 | Russia  |   1000 |
+----+---------+--------+

我们有多个用户在指定时间段内(例如 2 小时)移除兔子。(所以最少0个兔子,最多1000个兔子,兔子被退回,不是用户添加的)

我正在使用两个基本的事务查询,例如

BEGIN;
  UPDATE `BunnyTracker` SET `Bunnies`=`Bunnies`+1 where `id`=1;
COMMIT;

当有人归还兔子时,

BEGIN;
  UPDATE `BunnyTracker` SET `Bunnies`=`Bunnies`-1 where `id`=1 AND `Bunnies` > 0;
COMMIT;

当有人试图带走兔子时。我假设这些查询将在引擎盖下实现某种原子性

用户必须不能比每个国家/地区拥有更多的兔子(即,如果 23 个用户同时交易,则 -23 个兔子)

我的问题是,在这种情况下我如何保持 ACID 安全,同时能够同时添加/递增/递减 bunnies 字段,同时保持在范围内(0-1000)我可以将隔离级别设置为序列化,但我我担心这会影响性能。

有小费吗?提前致谢

4

2 回答 2

2

我相信您需要实现一些额外的逻辑来防止并发incrementdecrement事务都读取相同的初始值。

就目前而言,如果 Bunnies = 1,您可以同时进行增量和减量事务,它们都读取初始值 1。如果增量然后首先完成,其结果将被忽略,因为减量已经读取了初始值 1并将值递减为 0。这些操作中的任何一个最后完成都会有效地取消另一个操作。

要解决此问题,您需要使用 实现锁定读取,如此SELECT ... FOR UPDATE所述。例如:

BEGIN;
  SELECT `Bunnies` FROM `BunnyTracker` where `id`=1 FOR UPDATE;
  UPDATE `BunnyTracker` SET `Bunnies`=`Bunnies`+1 where `id`=1;
COMMIT;
于 2011-01-23T16:29:08.667 回答
1

尽管在用户看来,多个事务在数据库中同时发生,但它们实际上是连续的。(例如,一次将条目写入重做/事务日志)。

因此,对表“bunnies >= 0”设置约束并捕获试图违反该约束的事务失败对您有用吗?

于 2011-01-22T20:42:12.267 回答