想象一下,我们有一个表格如下,
+----+---------+--------+
| 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安全,同时能够同时添加/增加/减少兔子字段,同时保持在界限内(0-1000) 我可以将隔离级别设置为序列化,但我担心会破坏性能。
任何提示? 提前致谢
答案 0 :(得分:2)
我认为您需要实现一些额外的逻辑来防止并发increment
和decrement
事务都读取相同的初始值。
就目前而言,如果Bunnies = 1,你可以同时增加和减少事务,它们都读取初始值1.如果增量首先完成,其结果将被忽略,因为减量已经读取了初始值值为1并将值递减为0.无论这些操作最后完成哪一个都将有效地取消其他操作。
要解决此问题,您需要使用SELECT ... FOR UPDATE
实现锁定读取
描述here。例如:
BEGIN;
SELECT `Bunnies` FROM `BunnyTracker` where `id`=1 FOR UPDATE;
UPDATE `BunnyTracker` SET `Bunnies`=`Bunnies`+1 where `id`=1;
COMMIT;
答案 1 :(得分:1)
虽然看起来用户在数据库中同时发生多个事务,但它们实际上是顺序的。 (例如,条目一次一个地写入重做/事务日志)。
因此,您是否可以在表格“bunnies> = 0”上设置约束并捕获试图破坏该约束的交易失败?