3

次のようなテーブルがあると想像してください。

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

また、2時間などの指定された期間、複数のユーザーがバニーを削除しています。(したがって、最小0のバニー、最大1000のバニー、バニーが返されますが、ユーザーによって追加されることはありません)

私は次のような2つの基本的なトランザクションクエリを使用しています

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バニー)

私の問題は、この場合、バニーフィールドを同時に追加/インクリメント/デクリメントしながら、境界(0〜1000)内にとどまりながら、ACIDの安全性を維持するにはどうすればよいですか?分離レベルをシリアル化に設定できますが、私はmは、パフォーマンスが低下するのではないかと心配していました。

任意のヒント?前もって感謝します

4

2 に答える 2

2

increment並行トランザクションとdecrementトランザクションの両方が同じ初期値を読み取ら ないようにするには、いくつかの追加ロジックを実装する必要があると思います。

現状では、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

ユーザーには、DB内で複数のトランザクションが同時に発生しているように見えますが、実際にはシーケンシャルです。(たとえば、エントリは一度に1つずつREDO /トランザクションログに書き込まれます)。

したがって、テーブル「bunnies> = 0」に制約を設定し、その制約に違反しようとするトランザクションの失敗をキャッチすることは機能しますか?

于 2011-01-22T20:42:12.267 に答える