2011-01-22 5 views
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 в этом случае, имея возможность одновременно добавлять/увеличивать/уменьшать поле кроликов, оставаясь в пределах (0-1000) Я мог бы установить уровень изоляции в сериализованный, но я «Я беспокоюсь, что это убьет производительность.

Любые советы? Заранее спасибо

ответ

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; 
+0

А, спасибо, это то, что мне нужно! знак равно – Josh

1

Несмотря на то, что пользователи, подобные нескольким транзакциям, происходят одновременно в базе данных, они фактически являются последовательными. (Например, записи записываются в журналы повтора/транзакции по одному за раз).

Будет ли это работать для вас, чтобы установить ограничение на таблицу «bunnies> = 0» и уловить сбой транзакции, которая пытается нарушить это ограничение?

+0

Будет использовать ограничение – Josh