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
更新を実行するときに正しい値を使用しない限り?
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
に設定します。また、ほとんどの場合、並行性が向上します。