回答:
コミット読み取りは、読み取り時にコミットされたデータが読み取られることを保証する分離レベルです。それは単に、読者が中間のコミットされていない「ダーティー」な読み取りを見るのを制限するだけです。トランザクションが読み取りを再発行した場合に同じデータが見つかるとは限らず、データは読み取られた後に自由に変更できます。
反復可能読み取りはより高い分離レベルであり、コミットされた読み取りレベルの保証に加えて、読み取られたデータが変更されないことも保証します。トランザクションが同じデータを再度読み取る場合、以前に読み取られたデータが変更されていないことがわかります、読み取り可能です。
次の分離レベルであるシリアライズ可能性は、さらに強力な保証を提供します。すべての反復可能な読み取り保証に加えて、後続の読み取りで新しいデータが表示されないことも保証します。
たとえば、列Cが1行のテーブルTがあるとします。たとえば、値が「1」であるとします。次のような簡単なタスクがあるとします。
BEGIN TRANSACTION;
SELECT * FROM T;
WAITFOR DELAY '00:01:00'
SELECT * FROM T;
COMMIT;
これは、テーブルTから2つの読み取りを発行する単純なタスクであり、その間に1分の遅延があります。
上記のロジックに従うと、SERIALIZABLEトランザクションは簡単に実行できますが、行を変更、削除、挿入できないようにする必要があるため、可能なすべての同時操作を常に完全にブロックしていることがすぐにわかります。.Net System.Transactions
スコープのデフォルトのトランザクション分離レベルはシリアライズ可能であり、これは通常、結果として生じる極端なパフォーマンスを説明します。
そして最後に、SNAPSHOT分離レベルもあります。SNAPSHOT分離レベルでは、シリアライズ可能と同じ保証が行われますが、並行トランザクションがデータを変更できないようにする必要はありません。代わりに、すべての読者に独自のバージョンの世界(独自の「スナップショット」)を表示するように強制します。これにより、同時更新をブロックしないため、プログラミングが非常に簡単になるだけでなく、非常にスケーラブルになります。ただし、その利点には代償が伴います。それは、サーバーのリソース消費が増えることです。
補足的な読み取り:
データベースの状態は、トランザクションの開始から維持されます。session1で値を取得してから、その値をsession2で更新し、session1で再度取得すると、同じ結果が返されます。読み取りは繰り返し可能です。
session1> BEGIN;
session1> SELECT firstname FROM names WHERE id = 7;
Aaron
session2> BEGIN;
session2> SELECT firstname FROM names WHERE id = 7;
Aaron
session2> UPDATE names SET firstname = 'Bob' WHERE id = 7;
session2> SELECT firstname FROM names WHERE id = 7;
Bob
session2> COMMIT;
session1> SELECT firstname FROM names WHERE id = 7;
Aaron
トランザクションのコンテキスト内では、常に最後にコミットされた値を取得します。session1で値を取得し、session2で更新してから、session1で取得すると、session2で変更された値が取得されます。最後にコミットされた行を読み取ります。
session1> BEGIN;
session1> SELECT firstname FROM names WHERE id = 7;
Aaron
session2> BEGIN;
session2> SELECT firstname FROM names WHERE id = 7;
Aaron
session2> UPDATE names SET firstname = 'Bob' WHERE id = 7;
session2> SELECT firstname FROM names WHERE id = 7;
Bob
session2> COMMIT;
session1> SELECT firstname FROM names WHERE id = 7;
Bob
理にかなっていますか?
このスレッドへの私の読書と理解による単純な答えと@ remus-rusanuの答えは、この単純なシナリオに基づいています。
プロセスAとBの2つがあります。プロセスBはテーブルXを読み取っています。プロセスAはテーブルXに書き込んでいます。プロセスBはテーブルXを再度読み取っています。
既に受け入れられている答えを持つ古い質問ですが、SQL Serverのロック動作をどのように変更するかという観点から、これら2つの分離レベルについて考えたいと思います。これは、私と同じようにデッドロックをデバッグしている人に役立つかもしれません。
READ COMMITTED(デフォルト)
共有ロックはSELECTで取得され、SELECTステートメントが完了すると解放されます。これは、コミットされていないデータのダーティリードがないことをシステムが保証する方法です。SELECTが完了した後、トランザクションが完了する前に、他のトランザクションが基になる行を変更する可能性があります。
反復可能な読み取り
共有ロックはSELECTで取得され、トランザクションの完了後にのみ解放されます。これは、トランザクション中に読み取った値が変更されないことをシステムが保証できる方法です(トランザクションが完了するまでロックされたままであるため)。
この疑問を簡単な図で説明しようとしています。
コミット読み取り:この分離レベルでは、トランザクションT1はトランザクションT2によってコミットされたXの更新された値を読み取ります。
反復可能読み取り:この分離レベルでは、トランザクションT1はトランザクションT2によってコミットされた変更を考慮しません。
最初に受け入れられた解決策についての私の観察。
RRの下(デフォルトのmysql)-txが開いていて、SELECTが起動された場合、別のtxは、前のtxがコミットされるまで、以前のREAD結果セットに属する行を削除できません(実際には、新しいtxのdeleteステートメントがハングするだけです)。ただし、次のtxは問題なくテーブルからすべての行を削除できます。ところで、以前のtxの次のREADでは、コミットされるまで古いデータが表示されます。