web-dev-qa-db-ja.com

InnoDBと分離レベル-繰り返し可能な読み取りは悪いことではありませんか?

InnoDB's分離レベル そしてそれはほとんどの部分で理にかなっていますが、私が得られないのはなぜですかunrepeatable reads悪いこと?それは逆にしてはいけませんか?

たとえば:

たとえば、商品を販売するための在庫列があり、誰かが商品を購入するたびに、Repeatable readまたはserializable分離レベルでは、データの整合性が損なわれませんか?

例えば:

TX A: start transaction;
TX B: set session transaction isolation level repeatable read;
TX B: start transaction;
TX A: select stock from products;               -- val = 8
TX B: select stock from products;               -- val = 8
TX A: update products set stock = stock - 1;    -- val = 7
TX B: select stock from products;               -- val = 8
TX A: commit
TX B: select stock from products;               -- val = 8, incorrect!
TX B: commit;
TX B: select stock from products;               -- val = 7

更新を実行するときに正しい値を使用しない限り?

4
Brett

InnoDB分離レベルは「悪い」または「良い」ではなく、分離の観点からアプリケーションに必要なものによって異なります。

この例では、反復可能読み取りを使用することにより、最初の選択が完了すると、そのトランザクションの観点から、他のトランザクションがデータベースの状態を変更できないようにします。つまり、5行目の前に "START TRANSACTION WITH CONSISTENT SNAPSHOT"を実行したかのようになります。これはいくつかのケースで必要となる場合があり、例を挙げましょう。

TX A: START TRANSACTION;
TX A: SELECT * FROM products WHERE stock BETWEEN 4 AND 6; -- I see rows 4 and 6 only,
                                                          --  and I want to update those only   
TX B: START TRANSACTION;
TX B: INSERT INTO products (stock) VALUES (5);

TX A: UPDATE products SET stock = 3 WHERE stock BETWEEN 4 AND 6;
TX A: COMMIT; -- race condition
TX B: COMMIT;

InnoDBのREPEATABLE READを設定すると、AがコミットするまでTX Bが挿入時にロックされるため、ファントムリードが消えます。ただし、READ COMMITTEDを実行している場合、AまたはBが最初にコミットするかどうかに応じて異なる出力が得られます。これは、ACIDプロパティに違反し、アプリケーションが予期しないものである可能性があります。

特に、STATEMENTベースのレプリケーションではファントムリードは不要です。そのため、READ COMMITTEDがデフォルトレベルであり、他のデータベースではREAD COMMITTEDよりも厳密な動作があります(シリアライズ可能が必要な場合) InnoDBの動作を取得するため)。最初の選択が更新の場合、それらのトランザクションを個別に実行すると、異なる結果(スレーブのドリフト)が発生します。トランザクションは、アトミックかつシリアルにbinlogに書き込まれることに注意してください。

これらのケースはアプリケーションレベルで処理するため、ほとんどのアプリケーションでは必要ない場合があることに同意します。その場合は、ROWベースのレプリケーションを使用して、デフォルトのトランザクション分離レベルをREAD COMMITTEDに設定します。また、ほとんどの場合、並行性が向上します。

5
jynus