MySQLデータベースのトランザクションとロックの詳細な分析

MySQLデータベースのトランザクションとロックの詳細な分析

1. 基本概念

トランザクションは、ACID プロパティを満たす一連の操作です。トランザクションは、Commit によってコミットされ、Rollback によってロールバックされます。中間状態と一貫性のある状態(データベーステーブルに実際に存在する状態でもある)が存在します。

原子性: トランザクションは分割できない最小単位と見なされ、トランザクションのすべての操作は正常にコミットされるか、すべて失敗してロールバックされます。ロールバックは、トランザクションによって実行された変更操作を記録する UNDO ログを使用して実行できます。ロールバックすると、これらの変更操作を元に戻すことができます。

UndoLog: トランザクションのアトミック性を保証するために、データを操作する前に、まずデータを Undo ログにバックアップしてからデータを変更します。エラーが発生した場合、またはユーザーが ROLLBACK ステートメントを実行した場合、システムは Undo ログ内のバックアップを使用して、トランザクションが開始される前の状態にデータを復元できます。 REDO ログとは異なり、ディスク上には個別の UNDO ログ ファイルはありません。UNDO ログは、UNDO セグメントと呼ばれるデータベース内の特別なセグメントに格納されます。UNDO セグメントは共有表領域にあります。 Innodbは、レコードの各行に3つの隠しフィールドを実装しています。6バイトのトランザクションID(DB_TRX_ID)7バイトのロールバックポインタ(DB_ROLL_PTR)隠しID

一貫性: データベースは、トランザクションの実行前と実行後に一貫した状態を維持します。一貫性のある状態では、すべてのトランザクションは同じデータに対して同じ読み取り結果を持ちます。

分離: 1 つのトランザクションによって行われた変更は、最終的にコミットされるまで他のトランザクションには表示されません。

耐久性: トランザクションがコミットされると、行われた変更はデータベースに永久に保存されます。システムがクラッシュしても、トランザクション実行の結果は失われません。システムクラッシュが発生した場合、redoLog を使用して回復し、永続性を実現できます。データに対する論理的な変更を記録する undoLog とは異なり、redoLog はデータ ページに対する物理的な変更の概要を記録します。
1. 一貫性が満たされた場合にのみ、トランザクションの実行結果は正確になります。
2. 同時実行性がない場合、トランザクションは順次実行され、分離性が満たされます。このとき、原子性が満たされていれば、一貫性も満たされます。
3. 同時実行の場合、複数のトランザクションが並行して実行されます。トランザクションは、一貫性を満たすために、原子性だけでなく分離性も満たす必要があります。
4. システムクラッシュに対処するためにトランザクションは永続的である必要がある

3.自動コミット

MySQL はデフォルトで自動コミット モードを使用します。つまり、トランザクションを開始するために start transaction ステートメントを明示的に使用しない場合、各操作はトランザクションとして扱われ、自動的にコミットされます。

4. トランザクション分離レベル

コミットされていない読み取り: トランザクション内の変更は、コミットされていない場合でも他のトランザクションに表示されます。

コミットされた読み取り: トランザクションは、コミットされたトランザクションによって行われた変更のみを読み取ることができます。つまり、トランザクションによって行われた変更は、コミットされるまで他のトランザクションには表示されません。

反復可能読み取り: 同じトランザクションで同じデータを複数回読み取った結果が同じになることを保証します。直列化可能: トランザクションが直列に実行されるように強制し、複数のトランザクションが互いに干渉せず、同時一貫性の問題が起こらないようにします。この分離レベルでは、ロック メカニズムを使用して同時に 1 つのトランザクションのみが実行されるようにするため、つまりトランザクションが直列に実行されるようにするためにロックを実装する必要があります。

5. 同時実行の一貫性の問題

背景

同時実行環境では、トランザクションの分離を保証することが難しいため、多くの同時実行一貫性の問題が発生します。

メインシーン

変更の消失: 変更の消失とは、トランザクションの更新操作が別のトランザクションの更新操作に置き換えられることを意味します。たとえば、トランザクション T1 と T2 の両方がデータの一部を変更します。最初に T1 がデータを変更してコミットし、その後 T2 がデータを変更します。T2 の変更により、T1 の変更が上書きされます。
ビジネス シナリオ: ユーザーは、住所情報を変更したり、既定の住所を設定したり、住所を削除したりすることで、住所を変更できます。これらの 3 つのシナリオでは、同じ更新ステートメントが呼び出されます。ユーザーに提供されるアドレス更新用インターフェースは、ユーザーによるデフォルト アドレスの設定をサポートする必要があり、アドレス情報の更新用インターフェースとデフォルト アドレスの設定用インターフェースを別々に提供することはできません。別々に提供すると、上位レベルのサービス呼び出しによって実際には 2 つの更新インターフェースが同時に呼び出され、変更内容が失われる可能性が高くなります。

ダーティ データの読み取り: ダーティ データの読み取りとは、異なるトランザクションの下で、現在のトランザクションが他のトランザクションによってコミットされていないデータを読み取ることができることを意味します。たとえば、T1 はデータを変更しますが、コミットせず、その後 T2 がデータを読み取ります。 T1 がこの変更を元に戻すと、T2 によって読み取られたデータはダーティ データになります。

反復不可能な読み取り: 反復不可能な読み取りとは、トランザクション内で同じデータ セットを複数回読み取ることです。トランザクションが終了する前に、別のトランザクションも同じデータ セットにアクセスして変更を加えます。2 番目のトランザクションによる変更により、最初のトランザクションによって 2 回読み取られたデータに不整合が生じる可能性があります。たとえば、T2 がデータを読み取り、T1 がそのデータを変更します。 T2 がデータを再度読み取ると、この読み取り結果は最初の読み取り結果とは異なります。

ファントム リード: ファントム リードは、本質的には繰り返し不可能な読み取りです。T1 はデータの範囲を読み取り、T2 はこの範囲に新しいデータを挿入し、T1 はこの範囲のデータを再度読み取ります。この読み取りの結果は、最初の読み取りの結果とは異なります。

まとめ:
同時実行の不整合問題の主な原因は、トランザクションの分離が破壊されることです。解決策は、同時実行制御によって分離を確保することです。同時実行制御はブロッキングによって実現できますが、ブロッキング操作はユーザーが制御する必要があり、非常に複雑です。データベース管理システムはトランザクション分離レベルを提供し、ユーザーが同時一貫性の問題をより簡単に処理できるようにします。

6. ロック

ブロックの粒度:

行レベル ロック: すべてのリソースではなく、変更が必要なデータまたは行の一部のみがブロックされます。ロック競合の可能性は小さく、システムの同時実行性は高くなります。

テーブル レベルのロック: テーブル全体がロックされます。ロックされたデータの量が多すぎるため、ロック競合の可能性が大幅に高まり、システムの同時実行パフォーマンスが急激に低下します。

注意: ロックはリソースを消費します。すべてのロック操作 (ロックの取得、ロックの解放、ロック ステータスの確認など) は、システムのオーバーヘッドを増加させます。したがって、ロックの粒度が小さいほど、システムのオーバーヘッドは大きくなります。ロックの粒度を選択するときは、ロックのオーバーヘッドと同時実行性の間でトレードオフを行う必要があります。

ブロッキングタイプ

読み取り書き込みロック

ミューテックス ロックは、X ロックと略され、書き込みロックとも呼ばれます。
トランザクションはデータ オブジェクト A に X ロックを追加し、A の読み取りと更新が可能になります。ロック期間中、他のトランザクションは A にロックを追加できません。

共有ロックは S ロックと略され、読み取りロックとも呼ばれます。
トランザクションはデータ オブジェクト A に S ロックを追加します。A は読み取り可能ですが、更新はできません。ロック期間中、他のトランザクションは A に S ロックを追加できますが、X ロックを追加することはできません。

意図ロック

主にテーブルロックだが、実際にはロックではない

行レベル ロックとテーブル レベル ロックが存在する場合、トランザクション T がテーブル A に X ロックを追加する場合、まず他のトランザクションがテーブル A またはテーブル A 内の任意の行をロックしているかどうかを検出する必要があります。次に、テーブル A のすべての行をチェックする必要があり、非常に時間がかかります。
インテンション ロックは、元の X/S ロックに加えて IX/IS を導入します。IX/IS はどちらもテーブル ロックであり、トランザクションがテーブル内の特定のデータ行に X ロックまたは S ロックを追加することを示すために使用されます。
規定は2つあります。
トランザクションがデータ行オブジェクトに対して S ロックを取得する前に、まずテーブルに対して IS ロックまたはより強力なロックを取得する必要があります。
トランザクションがデータ行オブジェクトの X ロックを取得する前に、まずテーブルで IX ロックを取得する必要があります。
インテンション ロックを導入すると、トランザクション T がテーブル A に X ロックを追加する場合、最初に他のトランザクションがテーブル A に X/IX/S/IS ロックを追加したかどうかを検出するだけで済みます。追加されている場合は、他のトランザクションがこのテーブルまたはテーブル内の行のロックを使用しているため、トランザクション T は X ロックを追加できません。

IS/IX ロックは、実際のロックではなく、テーブルをロックする要求のみを示すため、相互に互換性があります。
ここでの互換性関係はテーブル レベルのロックに関するもので、テーブル レベルの IX ロックは行レベルの X ロックと互換性があります。2 つのトランザクションで 2 つのデータ行に X ロックを追加できます。
(トランザクション T1 はデータ行 R1 に X ロックを追加し、トランザクション T2 は同じテーブルのデータ行 R2 に X ロックを追加しようとしています。両方のトランザクションともテーブルに IX ロックを追加する必要がありますが、IX ロックは互換性があり、IX ロックは行レベルの X ロックとも互換性があります。したがって、両方のトランザクションは同じテーブル内の 2 つのデータ行を正常にロックして変更できます。)

7.MySQLの暗黙的および明示的なロック

暗黙的ロック: MySQL の InnoDB ストレージ エンジンは 2 段階のロック プロトコルを使用します。このプロトコルは、分離レベルに応じて必要なときに自動的にロックし、すべてのロックが同時に解除されます。これを暗黙的ロックと呼びます。

2 段階ロック プロトコル: ロックとロック解除は 2 段階に分かれています。シリアル化可能なスケジュールとは、同時実行制御により、同時に実行されたトランザクションの結果がシリアルに実行されたトランザクションの結果と同じになることを意味します。シリアルに実行されたトランザクションは互いに干渉せず、同時実行の一貫性の問題は発生しません。

または、特定のステートメントを使用して明示的なロックを実行します: SELECT ... LOCK In SHARE MODE; (共有ロック) SELECT ... FOR UPDATE; (排他ロック) トランザクションが完了してコミットされると、ロックは自動的に解除されます。

MySQL 3レベルブロッキングプロトコル

レベル 1 ロック プロトコル: トランザクション T がデータ A を変更する場合、変更内容が失われる問題を解決するために、X ロックを追加し、トランザクション T が終了した後にのみロックを解除する必要があります。現時点では、2 つのトランザクションが同時に同じデータを変更することはできません。そうしないと、トランザクションの変更が上書きされません。

レベル 2 ロック プロトコル: レベル 1 プロトコルに基づいて、データ A を読み取るときに S ロックを追加する必要があります。読み取り後すぐに S ロックを解除すると、ダーティ データの読み取りの問題を解決できます。トランザクションがデータ A を変更する場合、レベル 1 のロック プロトコルに従って X ロックが追加され、その後 S ロックを追加できないため、ダーティ データは読み込まれません。

レベル 3 ロック プロトコル: レベル 2 プロトコルに基づいて、データを読み取るときに S ロックを追加する必要があり、S ロックはトランザクションが完了した後にのみ解放できます。S ロックは、A を読み取るときに他のトランザクションが A に X ロックを追加できないため、読み取り中のデータの変更を回避し、繰り返し不可能な読み取りの問題を解決できます。

8. InnoDBエンジンのロック実装

MVCC

マルチバージョン同時実行制御は、MySQL の innoDB ストレージ エンジンが分離レベルを実装するための特定の方法です。コミット読み取りと繰り返し読み取りの 2 つの分離レベルを実装するために使用できます。コミットされていない読み取り分離レベルでは常に最新のデータ行が読み取られますが、要件は非常に低く、MVCC を使用する必要がありません。

ロックのセクションで述べたように、ロックは複数のトランザクションが同時に実行されるときに発生する同時一貫性の問題を解決できます。実際のシナリオでは、読み取り操作が書き込み操作を上回ることが多いため、不要なロック操作を避けるために読み取り/書き込みロックが導入されます。たとえば、読み取りと書き込みは相互に排他的ではありません。読み取り/書き込みロックでは、読み取り操作と書き込み操作は依然として相互に排他的であり、MVCC は複数バージョンの考え方を使用します。書き込み操作は最新バージョンのスナップショットを更新し、読み取り操作は古いバージョンのスナップショットを読み取ります。相互排他関係はなく、これは CopyOnWrite に似ています。

MVCC では、トランザクションの変更操作 (DELETE、INSERT、UPDATE) によって、データ行にバージョン スナップショットが追加されます。ダーティ リードと非反復リードが発生する最も基本的な理由は、トランザクションが他のトランザクションからコミットされていない変更を読み取ることです。トランザクションが読み取り操作を実行する場合、ダーティ リードと非反復読み取りの問題を解決するために、MVCC ではコミットされたスナップショットのみを読み取ることができるように規定されています。もちろん、トランザクションはコミットされていない独自のスナップショットを読み取ることができますが、これはダーティ リードとは見なされません。

システム バージョン番号 SYS_ID: 増加する番号です。新しいトランザクションが開始されるたびに、システム バージョン番号は自動的に増加します。

トランザクション バージョン番号 TRX_ID: トランザクション開始時のシステム バージョン番号。

MVCC のマルチバージョンとは、Undo ログに保存されるスナップショットの複数のバージョンを指します。ログは、ロールバック ポインター ROLL_PTR を介してデータ行のすべてのスナップショットを接続します。

INSERT、UPDATE、および DELETE 操作ではログが作成され、トランザクション バージョン番号 TRX_ID が書き込まれます。 DELETE は特別な UPDATE と見なすことができ、DEL フィールドも 1 に設定されます。

閲覧ビュー

MVCC は ReadView 構造を維持します。この構造には主に、現在のシステム内のコミットされていないトランザクションのリストと、リストの最小値と最大値が含まれます。

SELECT 操作を実行する場合、データ行スナップショットの TRX_ID と TRX_ID_MIN および TRX_ID_MAX の関係を使用して、データ行スナップショットが使用できるかどうかが判断されます。

TRX_ID < TRX_ID_MIN は、データ行のスナップショットが現在のすべてのコミットされていないトランザクションの前に変更されたため、使用できることを示します。

TRX_ID > TRX_ID_MAX は、トランザクションの開始後にデータ行スナップショットが変更されたため使用できないことを示します。

TRX_ID_MIN <= TRX_ID <= TRX_ID_MAX、分離レベルに応じて判断する必要がある

コミットされた読み取り: TRX_ID が TRX_IDs リストにある場合、データ行スナップショットに対応するトランザクションがコミットされていないため、スナップショットを使用できないことを意味します。それ以外の場合は送信済みであり、使用できます。

繰り返し読み取り: どちらも使用できません。使用できる場合、他のトランザクションもこのデータ行のスナップショットを読み取って変更できるため、現在のトランザクションがこのデータ行を読み取ったときに取得した値が変更され、反復不可能な読み取りの問題が発生することを意味します。データ行のスナップショットが利用できない場合は、Undo ログのロールバック ポインター ROLL_PTR に従って次のスナップショットを見つけ、上記の判断を実行する必要があります。

スナップショット読み取りとセーフ読み取り

スナップショット読み取り: MVCC の選択操作はスナップショット内のデータであり、ロック操作は必要ありません。

現在の読み取り: MVCCデータベースを変更するその他の操作では、最新のデータを読み取るためにロック操作が必要です。MVCCはロックを完全に回避するのではなく、選択のロック操作のみを回避することがわかります。

ロックを選択する必要がある場合は、前述の共有ロックや排他ロックなどのロック操作を強制することができます。

ネクストキーロック

概念: Next-Key Locks は、MySQL の InnoDB ストレージ エンジンのロック実装です。 MVCC ではファントム リードの問題を解決できませんが、この問題を解決するために Next-Key Locks が存在します。 REPEATABLE READ 分離レベルでは、MVCC + Next-Key Locks を使用するとファントム読み取りの問題を解決できます。

レコード ロック: レコード自体ではなく、レコードのインデックスをロックします。テーブルにインデックスがない場合、InnoDB は主キーに非表示のクラスター化インデックスを自動的に作成します。

ギャップ ロック: インデックス間のギャップをロックしますが、インデックス自体はロックしません。たとえば、トランザクションが次のステートメントを実行するとします: SELECT c FROM t WHERE c BETWEEN 10 and 20 FOR UPDATE;

ネクストキー ロック: レコード ロックとギャップ ロックを組み合わせたもので、レコードのインデックスをロックするだけでなく、インデックス間のギャップもロックします。前方が開いていて後方が閉じている範囲をロックします。たとえば、インデックスに 10、11、13、20 という値が含まれている場合、次の範囲をロックする必要があります: (-∞、10](10、11](11、13](13、20](20、+∞)

IX. 結論

上記の理論は数多くありますが、研究開発プロセス全体をサポートしています。さまざまなビジネスシナリオに遭遇したとき、データベースの分離レベルに基づいて、トランザクションがデッドロック、データの不整合、およびその他の理論的な問題を引き起こすかどうかを判断する必要があります。 MySQL の最も強力な機能は、パフォーマンスとデータ セキュリティの両方を考慮した RR [Repeatable Read] レベルでファントム リードを回避することです。
マイクロサービスまたは分散プロジェクトを開発する場合。対応する行が長時間ロックされないように、トランザクションをできるだけ単純に記述するようにしてください。これによりデータの一貫性も確保されます

これで、MySQL データベースのトランザクションとロックの詳細な分析に関するこの記事は終了です。MySQL データベースのトランザクションとロックに関するより関連性の高い情報については、123WORDPRESS.COM の以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • MySQL データベース テーブルのロック、ロック解除、およびトランザクションの削除の詳細な説明
  • MySQL データベースのインデックスとトランザクション
  • MySQL データベース トランザクション例のチュートリアル
  • MySQLデータベースのトランザクションとインデックスの詳細な説明
  • GolangはMySQLデータベーストランザクションの送信とロールバックを実装します
  • MySQL データベース トランザクションにおけるダーティ リード、ファントム リード、非反復リードの詳細な説明

<<:  ウェブサイトのデザインを改善するための役立つ提案を提供します

>>:  CentOS 7.x dockerはoverlay2ストレージ方式を使用する

推薦する

MySQL グリーンバージョン設定コードと 1067 エラーの詳細

MySQL グリーンバージョン設定コードと 1067 エラーMySQL エンコーディングを表示 &#...

MySQL ログインおよび終了コマンドの形式

mysql ログインのコマンド形式は次のとおりです。 mysql -h [hostip] -u [ユ...

Vue の要素カレンダー コンポーネントを使用したサンプル コード

まず効果図を見てみましょう: 完全なコードは添付されています <テンプレート> <...

Vueはシンプルなスライダー検証を実装する

この記事の例では、Vueスライダー検証の実装を共有しています。コードは次のとおりです。 <テン...

サーバーから返される14の一般的なHTTPステータスコードの詳細な説明

HTTP ステータス コードステータス コードは 3 桁の数字と理由フレーズ (最も一般的なもの: ...

マークアップ言語 - フレーズ要素

123WORDPRESS.COM HTML チュートリアル セクションに戻るには、ここをクリックして...

MySQL テーブルを返すとインデックスが無効になるケースの説明

導入MySQL InnoDB エンジンがレコードをクエリし、インデックス カバレッジを使用できない場...

よくある MySQL テーブル設計エラーの概要

目次間違い1: データの列が多すぎる誤解2: 共同クエリが多すぎる誤解3: ENUMの代わりにSET...

JavaScriptはクリックするとランダムなグラフィックを生成します

この記事では、クリックするとランダムグラフィックの生成を実現するJavaScriptの具体的なコード...

JavaScriptのアンチシェイクとスロットリングとは

目次1. 関数デバウンス1. 画像安定化とは何ですか? 2. 関数のスロットリング2.1 タイマーの...

JavaScript の寄生的構成継承についての簡単な説明

コンポジション継承組み合わせ継承は、疑似古典的継承とも呼ばれます。これは、昨日説明したプロトタイプ ...

Linux プラットフォームの MySQL でリモート ログインを有効にする

開発中、MySQL へのリモートアクセスでよく問題に遭遇します。そのたびに検索する必要があり、面倒に...

複数のサーバーにNginxリバースプロキシを実装する方法

Nginx は複数のサーバーをリバース プロキシします。つまり、nginx に異なるリクエストを送信...

フラットスタイルを使用してウェブサイトをデザインする方法

フラットなウェブサイト構造の本質はシンプルさです。コンテンツの重要なポイントを強調し、ページの装飾効...

Linuxで環境変数を削除する詳細な手順

Linuxで環境変数を削除するには?unsetコマンドを使用してすぐに削除します1. Linuxクラ...