web-dev-qa-db-ja.com

トランザクション分離レベルとテーブルのロックとの関係

私は約4レベルの分離を読みました。

Isolation Level       Dirty Read    Nonrepeatable Read  Phantom Read  
READ UNCOMMITTED      Permitted       Permitted           Permitted
READ COMMITTED              --        Permitted           Permitted
REPEATABLE READ             --             --             Permitted
SERIALIZABLE                --             --              --

私は理解したい各トランザクション分離がテーブルに対して取るロック

READ UNCOMMITTED - no lock on table
READ COMMITTED - lock on committed data
REPEATABLE READ - lock on block of sql(which is selected by using select query)
SERIALIZABLE - lock on full table(on which Select query is fired)

以下は、トランザクションの分離で発生する可能性のある3つの現象です。
ダーティリード-ロックなし
繰り返し不可の読み取り -コミット済みデータのロックとしてダーティリードなし
ファントムリード -SQLのブロックをロック(選択クエリを使用して選択)

理解したいこれらの分離レベルを定義する場所:jdbc/hibernateレベルまたはDBでも

PS: Oracleの分離レベル のリンクを調べましたが、不格好に見え、データベース固有の話をします

93
Java Geek

私は理解したいです各トランザクション分離がテーブルで取るロック

たとえば、3つの並行プロセスA、B、Cがあります。Aはトランザクションを開始し、データを書き込み、コミット/ロールバックします(結果に応じて)。 BはSELECTステートメントを実行してデータを読み取ります。 Cはデータを読み取り、更新します。これらのプロセスはすべて同じテーブルTで機能します。

  • READ UNCOMMITTED-テーブルのロックなし。書き込み中にテーブルのデータを読み取ることができます。これは、Aがデータを書き込む(コミットされていない)ことを意味し、Bはこのコミットされていないデータを読み取り、それを(あらゆる目的で)使用できることを意味します。 Aがロールバックを実行した場合、Bはまだデータを読み取って使用しています。これは物理的に関連しないテーブルにデータホールをもたらす可能性があるため、データを操作する最も高速ですが最も安全ではない方法です(はい、2つのテーブルは論理的にできますが、実際のアプリでは物理的に関連しません= \)。
  • READ COMMITTED-コミットされたデータをロックします。コミットされたデータのみを読み取ることができます。これは、Aがコミットを実行するまで、Aはデータを書き込み、BはAによって保存されたデータを読み取ることができないことを意味します。ここでの問題は、CがBで読み取られて使用されたデータを更新でき、Bクライアントには更新されたデータがないことです。
  • REPEATABLE READ-SQLのブロックをロックします(選択クエリを使用して選択されます)。これは、Bが何らかの条件(WHERE aField > 10 AND aField < 20)でデータを読み取り、AがaField値が10から20の間にデータを挿入し、その後Bがデータを再度読み取り、別の結果を取得することを意味します。
  • シリアライズ可能-完全なテーブルをロックします(選択クエリが起動されます)。これは、Bがデータを読み取り、他のトランザクションがテーブル上のデータを変更できないことを意味します。これは最も安全ですが、データを処理する最も遅い方法です。また、単純な読み取り操作はテーブルをロックするため、これは本番環境で大きな問題につながる可能性があります。Tテーブルは請求書テーブルであり、ユーザーXはその日の請求書とユーザーYが新しい請求書を作成したいので、Xが請求書の読み取りを実行している間、Yは新しい請求書を追加できません(そしてお金については、人々は本当に怒って、特に上司)。

これらの分離レベルを定義する場所を理解したい:JDBC/hibernateレベルまたはDBでも

JDBCを使用して、 Connection#setTransactionIsolation を使用して定義します。

Hibernateの使用:

<property name="hibernate.connection.isolation">2</property>

どこ

  • 1:コミットされていない読み取り
  • 2:コミットの読み取り
  • 4:繰り返し読み取り
  • 8:シリアライズ可能

Hibernate設定は here から取得されます(申し訳ありませんが、スペイン語です)。

ところで、RDBMSでも分離レベルを設定できます。

どんどん...

139
Luiggi Mendoza

Brb teaが言うように、データベースの実装と使用するアルゴリズムに依存します:MVCCまたはTwo Phase Locking。

CUBRID(オープンソースRDBMS) 説明 この2つのアルゴリズムのアイデア:

  • 二相ロック(2PL)

1つ目は、T2トランザクションがAレコードを変更しようとしたとき、T1トランザクションがすでにAレコードを変更したことを認識し、T1トランザクションがコミットされるかロールされるかをT2トランザクションが認識できないため、T1トランザクションが完了するまで待機する場合ですバック。この方法は、2フェーズロック(2PL)と呼ばれます。

  • マルチバージョン同時実行制御(MVCC)

もう1つは、T1トランザクションとT2トランザクションのそれぞれに、独自の変更されたバージョンを持たせることです。 T1トランザクションがAレコードを1から2に変更した場合でも、T1トランザクションは元の値1をそのままにして、AレコードのT1トランザクションバージョンが2であると書き込みます。その後、次のT2トランザクションはAレコードを変更します2から4ではなく1から3で、AレコードのT2トランザクションバージョンは3であると書き込みます。

T1トランザクションがロールバックされるとき、2、T1トランザクションバージョンがAレコードに適用されなくてもかまいません。その後、T2トランザクションがコミットされると、3、T2トランザクションバージョンがAレコードに適用されます。 T1トランザクションがT2トランザクションの前にコミットされると、Aレコードは2に変更され、T2トランザクションのコミット時に3に変更されます。最終的なデータベースステータスは、他のトランザクションに影響を与えることなく、各トランザクションを個別に実行するステータスと同じです。したがって、ACIDプロパティを満たします。この方法は、マルチバージョン同時実行制御(MVCC)と呼ばれます。

MVCCは、メモリ内のオーバーヘッドの増加を犠牲にして同時変更を可能にします(同じデータの異なるバージョンを維持する必要があるため)および計算(REPETEABLE_READレベルでは、更新を失うことができないため、Hiberateなどのデータのバージョンをチェックする必要があります) Optimistick Locking )で行います。

2PLでは トランザクション分離レベルは以下を制御します

  • データの読み取り時にロックを取得するかどうか、および要求するロックのタイプ。

  • 読み取りロックが保持される期間。

  • 別のトランザクションによって変更された行を参照する読み取り操作:

    • 行の排他ロックが解放されるまでブロックします。

    • ステートメントまたはトランザクションが開始されたときに存在していたコミットされたバージョンの行を取得します。

    • コミットされていないデータ変更を読み取ります。

トランザクション分離レベルを選択しても、データ変更を保護するために取得されるロックには影響しません。トランザクションは、変更されたデータに対して常に排他ロックを取得し、そのトランザクションに設定された分離レベルに関係なく、トランザクションが完了するまでそのロックを保持します。読み取り操作の場合、トランザクション分離レベルは主に、他のトランザクションによる変更の影響からの保護レベルを定義します。

分離レベルを低くすると、多くのユーザーが同時にデータにアクセスできるようになりますが、ダーティリードやロストなどの並行処理効果の数が増えますユーザーが遭遇する可能性のある更新。

SQL Server のロックと分離レベルの関係の具体例(READ_COMMITTED_SNAPSHOT = ONのREAD_COMMITEDを除く2PLを使用)

  • READ_UNCOMMITED:共有ロックを発行して、他のトランザクションが現在のトランザクションによって読み取られたデータを変更できないようにします。 READ UNCOMMITTEDトランザクションは、現在のトランザクションが変更されたが他のトランザクションによってコミットされていない行を読み取ることを妨げる排他ロックによってもブロックされません。 [...]

  • READ_COMMITED:

    • READ_COMMITTED_SNAPSHOTがOFF(デフォルト)に設定されている場合:共有ロックを使用して、現在のトランザクションが読み取り操作を実行している間、他のトランザクションが行を変更しないようにします。共有ロックは、他のトランザクションが完了するまで、他のトランザクションによって変更された行の読み取りをステートメントでブロックします。 [...]行ロックは、次の行が処理される前に解放されます。 [...]
    • READ_COMMITTED_SNAPSHOTがONに設定されている場合、データベースエンジンは行のバージョン管理を使用して、各ステートメントを、ステートメントの開始時に存在したトランザクションの一貫性のあるデータのスナップショットで提示します。ロックは、他のトランザクションによる更新からデータを保護するためには使用されません。
  • REPETEABLE_READ:共有ロックは、トランザクション内の各ステートメントによって読み取られたすべてのデータに適用され、トランザクションが完了するまで保持されます。

  • 直列化可能:範囲ロックは、トランザクションで実行される各ステートメントの検索条件に一致するキー値の範囲に配置されます。 [...]範囲ロックは、トランザクションが完了するまで保持されます。

8
gabrielgiussi

ロックは常にDBレベルで取得されます。

Oracle公式ドキュメント:-トランザクション中の競合を回避するために、DBMSはロックを使用します。これは、トランザクションがアクセスしているデータへのアクセスをブロックするメカニズムです。 (各ステートメントがトランザクションである自動コミットモードでは、ロックは1つのステートメントに対してのみ保持されることに注意してください。)ロックが設定された後は、トランザクションがコミットまたはロールバックされるまで有効のままです。たとえば、DBMSは、更新がコミットされるまでテーブルの行をロックできます。このロックの効果は、ユーザーがダーティリードを取得できないようにすることです。つまり、値が永続的になる前に値を読み取ることです。 (コミットされていない更新された値へのアクセスは、その値が以前の値にロールバックされる可能性があるため、ダーティー読み取りと見なされます。後でロールバックされる値を読み取る場合、無効な値を読み取ります。 )

ロックの設定方法は、トランザクション分離レベルと呼ばれるものによって決まります。これは、トランザクションをまったくサポートしないことから、非常に厳しいアクセスルールを適用するトランザクションをサポートすることまでさまざまです。

トランザクション分離レベルの一例として、TRANSACTION_READ_COMMITTEDがあります。これは、コミットされるまで値へのアクセスを許可しません。つまり、トランザクション分離レベルがTRANSACTION_READ_COMMITTEDに設定されている場合、DBMSはダーティリードの発生を許可しません。インターフェイスConnectionには、JDBCで使用できるトランザクション分離レベルを表す5つの値が含まれています。

4
Goyal Vicky