取引
トランザクションとは、開始と終了があるデータに対する一連の操作です。
トランザクションは、順次読み取りおよび書き込み操作です。 トランザクションの終了は、変更の保存(コミット、コミット)または変更のキャンセル(ロールバック、ロールバック)のいずれかです。 データベースに関連して、トランザクションは一連のクエリであり、単一のクエリとして扱われます。
トランザクションはACIDプロパティを満たしている必要があります
原子性。 トランザクションは、完全に実行されるか、まったく実行されません。
コヒーレンス。 トランザクションの終了時に、データに課された制限(たとえば、データベース内の制限)に違反してはなりません。 一貫性とは、システムが正しい状態から別の正しい状態に転送されることを意味します。
分離。 同時に実行されるトランザクションは、たとえば、別のトランザクションが使用するデータを変更するなど、相互に影響することはありません。 並列トランザクションの結果は、トランザクションが順次実行されたかのようになります。
持続可能性。 一度コミットすると、変更は失われません。
トランザクションログ
ログはトランザクションによって行われた変更を保存し、システム障害の場合にデータの原子性と安定性を保証します
ログには、トランザクションによる変更の前後にデータが持っていた値が含まれています。 先書きログ戦略では、開始前の以前の値と、トランザクションの完了後の最終値についての記録をログに追加する必要があります。 システムが突然シャットダウンした場合、データベースはログを逆の順序で読み取り、トランザクションによって行われた変更を破棄します。 中断されたトランザクションに遭遇すると、データベースはそれを実行し、ログでそれに関する変更を行います。 障害発生時の状態にあるデータベースは、ログを直接の順序で読み取り、トランザクションによって行われた変更を返します。 したがって、すでにコミットされたトランザクションの安定性と、中断されたトランザクションの原子性は保持されます。
エラーのあるトランザクションを単に再実行するだけでは回復できません。
例。 ユーザーのアカウントには500ドルがあり、ユーザーはATMを介して引き出します。 2つのトランザクションが実行されます。 最初は残高の値を読み取り、残高に十分な資金がある場合、ユーザーにお金を提供します。 2番目は、必要な金額を残高から減算します。 システムがクラッシュし、最初の操作が失敗し、2番目の操作が失敗するとします。 この場合、正のバランスでシステムを元の状態に戻すことなく、ユーザーにお金を再発行することはできません。
分離レベル
コミット済みデータの読み取り
ダーティリーディングの問題は、トランザクションが別のトランザクションの中間結果を読み取ることができることです。
例。 残高の初期値は0ドルです。 T1は50ドルを残高に追加します。 T2は残高値($ 50)を読み取ります。 T1は変更をキャンセルして終了します。 T2は、不正確なバランスデータで実行を続けます。
ソリューションはRead Committedで、トランザクションによって変更されたデータの読み取りを禁止します。 トランザクションAが何らかのデータセットを変更した場合、トランザクションBは、トランザクションAがこのデータにアクセスするのを強制的に待機させます。
反復可能読み取り
失われた変更(ロストアップデート)の問題。 T1は、T2への変更に対する変更を保存します。
例。 初期残高値は0ドルで、2つのトランザクションが同時に残高を補充します。 T1とT2は残高0ドルを読み取ります。 次に、T2は$ 200を$ 0に追加し、結果を保存します。 T1は$ 0に$ 100を追加し、結果を保存します。 合計結果は300ドルではなく100ドルです。
繰り返し不可能な読み取りの問題。 同じデータを繰り返し読み取ると、異なる値が返されます。
例。 T1は0ドルの残高値を読み取ります。 その後、T2は50ドルを残高に追加して終了します。 T1はデータを再度読み取り、前の結果との不一致を検出します。
繰り返し読み取りは、繰り返し読み取りが同じ結果を返すことを保証します。 あるトランザクションで読み取られたデータは、トランザクションが完了するまで他のトランザクションで変更することは禁止されています。 トランザクションAが何らかのデータセットを読み込んだ場合、トランザクションBは、このデータにアクセスするときに、トランザクションAが完了するのを待たなければなりません。
整然とした読書(シリアル化可能)
ファントムリード ある条件でデータを選択する2つのクエリは、異なる値を返します。
例。 T1は、残高が0ドル以上100ドル未満のすべてのユーザーの数を求めます。 T2は、残高が101ドルのユーザーから1ドルを引きます。 T1は要求を再実行します。
整然とした読み取り(シリアル化可能)。 トランザクションは完全にシーケンシャルに実行されます。 リクエストの条件に従うレコードを更新および追加することは禁止されています。 トランザクションAがテーブル全体のデータを要求した場合、トランザクションAまで残りのトランザクションではテーブル全体が凍結されます。
スケジューラー
並列トランザクションで操作を実行する順序を設定します
指定されたレベルの分離を提供します。 演算の結果がそれらの順序に依存しない場合、そのような演算は交換可能(置換可能)です。 コマンドは、異なるデータに対する読み取りおよび操作です。 読み取り/書き込みおよび書き込み/書き込み操作は可換ではありません。 スケジューラのタスクは、実行の結果がトランザクションの順次実行と同等になるように、並列トランザクションによって実行される操作を交互にすることです。
同時実行制御メカニズム
競合の検出と解決に基づく楽観的、競合の防止に基づく悲観的
楽観的なアプローチでは、複数のユーザーがデータのコピーを自由に使用できます。 編集を完了した最初の人が変更を保存し、残りは変更をマージする必要があります。 楽観的なアルゴリズムにより競合が発生しますが、システムは競合から回復する必要があります。
悲観的なアプローチでは、最初にデータをキャプチャしたユーザーは、他のユーザーがデータを受信できないようにします。 競合がまれな場合は、より高いレベルの並列処理を提供するため、楽観的な戦略を選択するのが賢明です。
ロック
1つのトランザクションがデータをブロックした場合、残りのトランザクションはデータにアクセスするときにデータにアクセスする必要があります
ブロックは、データベース、テーブル、行、または属性に重ねることができます。 共有ロック(共有ロック)は、複数のトランザクションによって同じデータに課せられ、すべてのトランザクション(課されたものを含む)の読み取りを許可し、変更および排他的キャプチャを禁止します。 排他ロックは、1つのトランザクションによってのみ課せられ、課せられたトランザクションのアクションを許可し、残りのアクションを禁止します。
デッドロックは、トランザクションが無期限に続くスタンバイモードの状態です。
例。 最初のトランザクションは2番目のトランザクションによってキャプチャされたデータのリリースを待っており、2番目のトランザクションは最初のトランザクションによってキャプチャされたデータのリリースを待っています。
デッドロックの問題に対する楽観的な解決策により、デッドロックが発生しますが、デッドロックに関係するトランザクションの1つをロールバックしてシステムを復元します
特定の頻度で、デッドロックの検索が実行されます。 検出方法の1つは時間指定されています。つまり、トランザクションに時間がかかりすぎる場合にデッドロックが発生したと見なします。 デッドロックが見つかると、トランザクションの1つがロールバックされ、デッドロックに関係する他のトランザクションが完了できるようになります。 被害者の選択は、トランザクションの価値またはその年功序列(Wait-DieおよびWound-waitスキーム)に基づいて行うことができます。
各トランザクションTには 、トランザクションの開始時間を含むタイムスタンプTS が割り当てられます。
ウェイトダイ
TS(Ti) < TS(Tj)の場合、 Tiは待機します。それ以外の場合、 Tiはロールバックし、同じタイムスタンプで再び開始します。
若いトランザクションがリソースをキャプチャし、古いトランザクションが同じリソースを要求している場合、古いトランザクションが期待されます。 古いトランザクションがリソースをキャプチャした場合、このリソースを要求する若いトランザクションはロールバックされます。
傷を待つ。
TS(Ti) < TS(Tj)の場合、 Tjはロールバックし、同じタイムスタンプで再び開始します。それ以外の場合、 Tiは待機します。
若いトランザクションがリソースをキャプチャし、古いトランザクションが同じリソースを要求している場合、若いトランザクションはロールバックされます。 古いトランザクションがリソースをキャプチャした場合、このリソースを要求する若いトランザクションは待機できます。 被害者の年功序列ベースの選択により、デッドロックは防止されますが、インターロック状態にないトランザクションはロールバックされます。 問題は、トランザクションが何度もロールバックされる可能性があることです。 古いトランザクションは、リソースを長時間保持できます。
デッドロックの問題に対する悲観的な解決策により、デッドロックのリスクがある場合にトランザクションが開始されなくなります。
デッドロックを検出するために、グラフ(待機グラフ、待機グラフ)が構築されます。その頂点はトランザクションであり、エッジは、データの解放を待機しているトランザクションからこのデータをキャプチャしたトランザクションに向けられます。 グラフがループするとデッドロックが発生したと考えられています。 特に分散データベースで待機グラフを作成することは、費用のかかる手順です。
2フェーズロック-トランザクションの開始時にトランザクションが使用するすべてのリソースをキャプチャし、終了時にそれらを解放することにより、デッドロックを防止します。
すべてのブロック操作は、最初のロック解除の前に行う必要があります。 グラブのキャプチャが発生する成長フェーズと、グラブのリリースが発生する縮小フェーズの2つのフェーズがあります。 リソースの1つをキャプチャーできない場合、トランザクションが再び開始されます。 複数のトランザクションが同じリソースを求めて競合する場合など、トランザクションが必要なリソースをキャプチャできない可能性があります。
2フェーズコミットにより、すべてのデータベースレプリカでコミットが実行されます。
各データベースは、ログに変更されるデータに関する情報を入力し、コーディネーターのOK(投票フェーズ)に対応します。 全員がOKと答えた後、コーディネーターは全員にコミットを義務付けるシグナルを送信します。 サーバーをコミットした後、彼らはOKと応答し、少なくとも1人がOKと答えなかった場合、コーディネーターはすべてのサーバーへの変更をキャンセルする信号を送信します(完了フェーズ)。
タイムスタンプ方式
若いトランザクションに関係するデータにアクセスしようとすると、古いトランザクションがロールバックします
各トランザクションには、実行の開始時間に対応するTSタイムスタンプが割り当てられます。 Tiが Tjよりも古い場合、 TS(Ti) < TS(Tj) 。
トランザクションがロールバックされると、新しいタイムスタンプが割り当てられます。 トランザクションに関係する各データオブジェクトQには、2つのラベルが付いています。 W-TS(Q)は、 Qに正常に書き込まれた最も若いトランザクションのタイムスタンプです。 R-TS(Q)は、 Qで読み取りレコードを完了した最も若いトランザクションのタイムスタンプです。
トランザクションTがQデータの読み取りを要求する場合、2つのオプションが可能です。
TS(T) < W-TS(Q) 、つまり、より若いトランザクションによってデータが更新された場合、トランザクションTはロールバックされます。
TS(T) > = W-TS(Q)の場合、読み取りが実行され、 R-TS(Q)はMAX(R-TS(Q)、TS(T))になります。
トランザクションTがデータQの変更を要求する場合、2つのオプションが可能です。
TS(T) < R-TS(Q)の場合、つまり、データがすでに若いトランザクションによって読み取られており、変更が行われた場合、競合が発生します。 トランザクションTはロールバックします。
TS(T) < W-TS(Q) 、つまり、トランザクションが新しい値を上書きしようとすると、トランザクションTはロールバックします。 その他の場合、変更が実行され、 W-TS(Q)がTS(T)と等しくなります。
高価な待機グラフの構築は必要ありません。 古いトランザクションは新しいトランザクションに依存しているため、待機列にループはありません。 トランザクションは予期せず、すぐにロールバックされるため、デッドロックはありません。 カスケードキックバックが可能です。 Tiがロールバックし、 TjがTiが変更したデータを読み取った場合、 Tjもロールバックする必要があります。 同時に、Tjがすでにコミットされている場合、安定性の原則に違反します。
カスケードロールバックの1つのソリューション。 トランザクションはすべての書き込み操作を最後に実行し、残りのトランザクションはこの操作の完了を待つ必要があります。 トランザクションは読み取り前にコミットを待機しています。
トーマス書き込み規則-より若いトランザクションによって更新されたデータが古いトランザクションによって上書きされることを許可されないタイムスタンプ方式のバリエーション
トランザクションTは、データQの変更を要求します。 TS(T) < W-TS(Q) 、つまり、トランザクションが新しい値を上書きしようとしている場合、タイムスタンプメソッドのようにトランザクションTはロールバックされません。