5分でMySQLの同時実行制御とトランザクションの原則の詳細な説明


今日のインターネットビジネスで最も広く使用されているデータベースは、間違いなくリレーショナルデータベースMySQLです。「または」という単語を使用する理由は、TIDB、OceanBaseなどの国内データベース分野も近年大きな進歩を遂げているためです。分散データベースですが、まだ絶対的なカバレッジを形成していないため、この段階では、作業中に発生したいくつかの問題に対処するためにMySQLデータベースを学習し続け、インタビュー中にデータベース部分を調査する必要があります。

今日のコンテンツでは、MySQLデータベースの同時実行制御、トランザクション、およびストレージエンジンの主要な問題について説明します。このコンテンツに関連するナレッジグラフを次の図に示します。

同時実行制御

同時実行制御は大きなトピックです。コンピュータソフトウェアシステムで同時にデータを変更する複数の要求がある限り、Javaのマルチスレッドセキュリティなどの同時実行制御の問題が発生します。MySQLの同時実行制御では、主に、データベースがテーブルデータの同時読み取りと書き込みを制御する方法について説明します。

たとえば、構造が次のテーブルuseraccountがあります。

この時点で、次の2つのSQLステートメントがデータベースへの要求を同時に開始した場合:

SQL-A:

update useraccount t set t.account=t.account+100 where username='wudimanong';

SQL-B:

update useraccount t set t.account=t.account-100 where username='wudimanong'

上記のすべてのステートメントを実行すると、正しい結果はaccount = 100になるはずですが、同時実行の場合、このような状況が発生する可能性があります。

では、MySQLの同時実行制御はどのようになっているのでしょうか。実際、ほとんどの同時実行制御方法と同様に、ロックメカニズムは同時実行制御を実現するためにMySQLでも使用されます。

1.MySQLロックタイプ

MySQLでは、同時実行制御は主に「読み取り/書き込みロック」によって実現されます。

**読み取りロック:**共有ロックとも呼ばれ、複数の読み取り要求でロックを共有して、ブロックせずに同時にデータを読み取ることができます。

**書き込みロック:**排他ロックとも呼ばれます。書き込みロックは、ロックを取得する他のすべての要求を除外し、書き込みが完了してロックが解放されるまでブロックします。

読み取り/書き込みロックは、並列の読み取りと読み取りを実現できますが、並列の読み取り、書き込み、および書き込みを実現することはできません。後述するトランザクションの分離は、読み取り/書き込みロックに基づいて実現されます。

2.MySQLロックの粒度

上記の読み取り/書き込みロックは、MySQLのロックタイプに応じて分類され、読み取り/書き込みロックが課すことができる粒度は、主にデータベース内のテーブルと行に反映されます。これは、テーブルロックと行ロックとも呼ばれます。 )

テーブルロック(テーブルロック):MySQLの最も基本的なロック戦略です。テーブル全体をロックするため、ロックを維持するためのオーバーヘッドは最小限に抑えられますが、テーブルの読み取りと書き込みの効率が低下します。ユーザーがテーブルロックを介してテーブルへの書き込み操作(挿入、削除、更新)を実装する場合、最初にテーブルをロックする書き込みロックを取得する必要があります。この場合、他のユーザーによるテーブルの読み取りと書き込みはブロックされます。 。通常の状況では、「altertable」などのステートメントはテーブルロックを使用します。

行ロック:行ロックは、最大の範囲で同時読み取りと書き込みをサポートできますが、データベース保守ロックのオーバーヘッドは比較的大きくなります。行ロックは、私たちの日常生活で最も一般的に使用されるロック戦略です。一般に、MySQLの行レベルのロックは、MySQLサーバーレベルではなく、特定のストレージエンジンによって実装されます(テーブルロックはMySQLサーバーレベルで実装されます)。

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

MVCC(MultiVersion Concurrency Control)、マルチバージョン同時実行制御。ほとんどのMySQLトランザクションエンジン(InnoDBなど)では、行レベルのロックは単純に実装されていません。そうでない場合、次のような状況が発生します。「特定のユーザー(行レベルの書き込みロックを取得)によってデータAが更新されている間、他のユーザーこのデータの読み取り(読み取りロックの取得)はブロックされます」。しかし、現実は明らかにそうではありません。これは、MySQLストレージエンジンが同時実行パフォーマンスの向上を考慮しているためです。MVCCデータマルチバージョン制御により、読み取りと書き込みの分離が実現され、データをロックなしで読み取り、読み取りと書き込みを並列に実行できます。

例として、InnoDBストレージエンジンのMVCC実装を取り上げます。

InnoDBのMVCCは、レコードの各行の後ろに2つの非表示の列を格納することによって実装されます。これらの2つの列のうち、1つは行の作成時間を保持し、もう1つは行の有効期限を保持します。もちろん、それらが保存するのは実際の時間値ではなく、システムのバージョン番号です。新しいトランザクションが開かれるたびに、システムバージョン番号が自動的にインクリメントされます。トランザクションの開始時のシステムバージョン番号は、クエリの各行のバージョン番号と比較するためのトランザクションのバージョン番号として使用されます。

MVCCがMySQLで依存している主な意味は、「ログの取り消しとビューの読み取り」です。

  • 元に戻すログ:元に戻すログは、データ行の複数のバージョンを記録するために使用されます。

  • ビューの読み取り:データの現在のバージョンの可視性を判断するために使用されます

元に戻すログは、トランザクションの後半で導入されます。MVCCの読み取りと書き込みの原理の概略図は次のとおりです。

上の図は、MySQL InnoDBストレージエンジンを示しています。REPEATABLEREAD(繰り返し可能な読み取り)トランザクション分離レベルでは、2つの追加のシステムバージョン番号(行作成バージョン番号、行削除バージョン番号)が保存されます。 MVCCを実現して、ほとんどの読み取り操作を追加のロックなしで読み取ることができるようにします。この設計により、データの読み取り操作がより簡単になり、パフォーマンスが向上します。

では、MVCCモードでのデータ読み取り操作により、データが正しく読み取られるようにするにはどうすればよいでしょうか。InnoDBを例にとると、レコードの各行は、選択時に次の2つの条件に従ってチェックされます。

  • バージョン番号が現在のトランザクションバージョン以下のデータ行のみを検索します。これにより、トランザクションによって読み取られた行が、トランザクションの開始前に存在していたか、トランザクション自体によって挿入または変更されたことが保証されます。

  • 行の削除バージョン番号が未定義であるか、現在のトランザクションバージョン番号よりも大きいです。これにより、トランザクションによって読み取られた行が、トランザクションの開始前に削除されないことが保証されます。

クエリの結果として返されるのは、上記の2つの条件を満たすレコードのみです。図に示すロジックを例にとると、書き込み要求でアカウントを200に変更するプロセスで、InnoDBは新しいレコード(account = 200)を挿入し、現在のシステムバージョン番号を行作成バージョン番号(createVersion = 2)として使用します。同時に、現在のシステムバージョン番号がバージョン番号を削除するための元の行として使用され(deleteVersion = 2)、次のように、このデータのデータコピーには2つのバージョンがあります。

書き込み操作が終了していない場合、トランザクションは他のユーザー用です。一時的に非表示になります。選択チェック条件によると、accout = 100のレコードのみが対象となるため、クエリ結果はaccount = 100のレコードを返します。

上記のプロセスは、MVCCの実装に関するInnoDBストレージエンジンの基本原則ですが、MVCCマルチバージョン同時実行制御のロジックはREPEATABLE READ(繰り返し可能読み取り)」と「READCOMMITED(コミット読み取り)」2つのトランザクション分離レベルでのみ機能することに注意する必要がありますので、他の二つの分離レベルは、MVCCと互換性のないREAD UNCOMMITED(非コミット読み出し)と、常に現在のトランザクションのバージョンに準拠している最新のデータ列ではなく、データの行を読み出しSERIALIZABLEが全て読み取られた行に追加しますロックはMVCCの考え方に準拠していません。

MySQLトランザクション

MySQLの同時実行制御のプロセスに関する前回の説明では、トランザクション関連のコンテンツについても説明しました。次に、トランザクションに関するコア知識をより包括的に整理しましょう。

誰もが日々の開発プロセスでデータベーストランザクションを使用しており、トランザクションの特性であるACIDについて口を開くことができると思います。では、トランザクション内でどのように実装されますか?次のコンテンツでは、この問題について詳しくお話ししましょう。

1.事業概要

データベーストランザクション自体によって達成される効果は、主に次の2つの側面に反映されます。**「信頼性」「同時処理」**。

  • 信頼性:データベースは、挿入または更新操作が例外をスローした場合、またはデータベースがクラッシュした場合に、データ操作が一貫していることを確認する必要があります。

  • 同時処理:複数の同時要求が着信し、要求の1つがデータの変更である場合、他の要求がダーティデータを読み取らないようにするには、トランザクション間で読み取りと書き込みを分離する必要があります。

MySQLデータベーストランザクション機能を実現するための3つの主要なテクノロジ、つまりログファイル(ログのやり直しとログの取り消し)、ロックテクノロジ、およびMVCCがあります。

2.やり直しログ与元ログ

やり直しログと元に戻すログは、MySQLトランザクション機能を実現するためのコアテクノロジーです。

1)、やり直しログ

やり直しログはやり直しログと呼ばれ、トランザクションの耐久性を実現するための鍵です。REDOログログファイルは、主に2つの部分で構成されています。REDOログバッファ(Redoログバッファ)、REDOログファイル(ReDoログファイル)です。

MySqlのデータベースパフォーマンスを向上させるために、すべての変更はリアルタイムでディスクに同期されるのではなく、「Boffer Pool」と呼ばれるバッファープールに保存され、バックグラウンドスレッドを使用してバッファープールとディスクが実装されます。間の同期。

このモードを採用すると、このような問題が発生する可能性があります。データが同期される前にダウンタイムまたは停電が発生すると、コミットされたトランザクションの変更情報が失われる可能性があります。そして、この状況はデータベースソフトウェアには受け入れられません。

したがって、REDOログの主な機能は、正常にコミットされたトランザクションの変更情報を記録することであり、トランザクションの送信後にREDOログをディスクにリアルタイムで保持するため、システムの再起動後にREDOログを読み取って最新のデータを復元できます。

次に、次の図に示すように、SQL-Aによって開かれたトランザクションを例として取り上げ、REDOログがどのように機能するかを示します。

上の図に示すように、レコードの行を変更するトランザクションが開かれると、MySQLストレージエンジンはからデータを削除します。ディスクは変更のためにメモリのバッファプールに読み込まれます。このとき、メモリ内のデータが変更され、ディスク内のデータが異なります。この種の差分データは**「ダーティページ」**とも呼ばれます。

一般に、ストレージエンジンは、ダーティページが生成されるたびにダーティページをディスクにフラッシュしませんが、バックグラウンドスレッド**「マスタースレッド」**を使用して、およそ1秒に1回または10秒に1回実行します。ディスクを更新する頻度。この場合、データベースがダウンしているか電源が切れていると、ディスクにフラッシュバックされていないデータが失われる可能性があります。

REDOログの役割は、メモリとディスクの速度差を調整することです。トランザクションが送信されると、ストレージエンジンは、最初に変更するデータをREDOログに書き込み、次にバッファープール内の実際のデータページを変更して、データ同期をリアルタイムで更新します。このプロセス中にデータベースがハングした場合、REDOログの物理ログファイルにトランザクションの変更が記録されているため、データベースの再起動後に、REDOログに基づいてトランザクションデータを回復できます。

2)、元に戻すログ

上記では、主にデータを復元し、コミットされたトランザクションの永続性を確保するために使用されるREDOログログについて説明しました。MySQLには、ロールバックログとも呼ばれるもう1つの非常に重要なログタイプの元に戻すログがあります。これは主に、データが変更される前に情報を記録するために使用されます。これは、データが変更された後に情報を記録するREDOログの反対です。

元に戻すログは、主に以前のバージョンのトランザクション変更のデータ情報を記録します。システムエラーまたはロールバック操作によってロールバックされた場合、元に戻すログログに従って、データを変更前の状態にロールバックできます。

データが書き込まれるか変更されるたびに、ストレージエンジンは、変更前に情報を元に戻すログに記録します。

3.トランザクションの実現

以前、ロック、マルチバージョン同時実行制御(MVCC)、REDOログ、およびUNDOログについて説明しました。これらは、MySQLがデータベーストランザクションを実装するための基礎です。トランザクションの4つの主要な特性から、対応する関係は主に次のように反映されます。

実際、トランザクションの原子性、耐久性、および分離の最終的な目標は、トランザクションデータの一貫性を確保することです。ACIDは単なる概念であり、トランザクションの最終的な目標は、データの信頼性と一貫性を確保することです。

次に、トランザクションのACID機能の実装原理を分析します。

1)、原子性の実現

アトミシティとは、トランザクションを分割できない最小単位と見なす必要があることを意味します。トランザクション内のすべての操作が正常に実行されるか、すべて失敗してロールバックされます。トランザクションが操作の一部のみを実行することはできません。これはトランザクションアトミック性の概念。

MySQLデータベースの原子性は、主にロールバック操作によって実現されます。いわゆるロールバック操作では、エラーが発生した場合、またはロールバックステートメントが明示的に実行された場合、データを元の外観に復元する必要があり、このプロセスは元に戻すログを使用して実行する必要があります。具体的なルールは次のとおりです。

  • 各データ変更(挿入/更新/削除)操作には、元に戻すログの生成が伴い、ロールバックログはデータの前にディスクに保持する必要があります。

  • いわゆるロールバックとは、元に戻すログログに基づいて逆方向の操作を実行することです。たとえば、削除の逆方向の操作は挿入、挿入の逆方向の操作は削除、更新の逆方向の操作は更新などです。

2)、永続性の実現

永続性とは、トランザクションがコミットされると、加えられた変更がデータベースに永続的に保存されることを意味します。この時点で、システムがクラッシュしても、変更されたデータは失われません。

トランザクションの耐久性は、主にREDOログによって実現されます。REDOログログは、主に次の特性があるため、キャッシュ同期によって発生したデータの違いを補うことができます。

  • REDOログの保存はシーケンシャルですが、キャッシュの同期はランダムな操作です。

  • キャッシュの同期はデータページに基づいており、毎回送信されるデータのサイズはREDOログよりも大きくなります。

トランザクションの永続性を実現するためのREDOログのロジックについては、この記事の前半にあるREDOログの内容を参照してください。

3)、分離の実現

分離は、トランザクションのACID特性の中で最も複雑です。SQL標準では、4つの分離レベルが定義されています。各分離レベルは、トランザクションの変更を指定します。これらはトランザクション間で表示され、非表示になります。

4つのMySQL分離レベル(低から高)があります。

  • READ UNCOMMITED(READ UNCOMMITED);

  • コミット済みを読む

  • REPEATABLE READ(繰り返し可能な読み取り)

  • SERIALIZABLE(シリアル化可能)

分離レベルが低いほど、データベースが実行できる同時実行性は高くなりますが、実装の複雑さとオーバーヘッドは大きくなります。分離レベルとその実装原則を完全に理解している限り、ACIDでのトランザクション分離を理解することと同じです。

前述のように、アトミック性、永続性、および分離の目的は、最終的にデータの一貫性を実現することですが、分離は他の2つとは異なります。アトミック性と永続性は、主にデータの信頼性を確保することです。たとえば、ダウンタイム後のデータリカバリやエラー後のデータロールバックなどです。分離の中心的な目標は、複数の同時読み取りおよび書き込み要求のアクセスシーケンスを管理して、データベースデータへの安全で効率的なアクセスを実現することです。これは、本質的にデータのセキュリティとパフォーマンスの間のトレードオフゲームです。

信頼性の高い分離レベル、同時実行パフォーマンスの低さ(たとえば、すべての読み取りと書き込みがロックされるため、SERIALIZABLE分離レベル)、信頼性の低さ、同時実行パフォーマンスの高さ(たとえば、読み取りと書き込みがまったくロックされないため、READ UNCOMMITED)。

次に、これら4つの分離レベルの特性を個別に分析します。

コミットされていない読み取り

READ UNCOMMITTED分離レベルでは、トランザクションの変更がコミットされていない場合でも、他のトランザクションに表示されます。つまり、トランザクションはコミットされていないデータを読み取ることができます。

読み取りではロックが追加されないため、書き込み操作で読み取りプロセス中にデータが変更されると、「ダーティ読み取り」が発生します。コミットされていない読み取り分離レベルの読み取りと書き込みの図は次のとおりです。

上の図に示すように、書き込み要求はアカウントを200に変更し、トランザクションはこの時点ではコミットされていません。ただし、読み取り要求はコミットされていないトランザクションデータaccount = 200を読み取ることができます。その後、書き込み要求トランザクションは失敗します。 account = 100をロールバックすると、この時点で読み取り要求によって読み取られたaccount = 200のデータはダーティデータになります。

この分離レベルの利点は、読み取りと書き込みの並列処理と高性能ですが、欠点は、ダーティ読み取りが発生しやすいことです。したがって、この分離レベルは、MySQLデータベースでは一般的に採用されていません。

コミット済みを読む

このトランザクション分離レベルは、**「繰り返し不可の読み取りまたはコミット読み取り」とも呼ばれます。**その特徴は、コミットされる前のトランザクションのすべての変更が他のトランザクションから見えないことです。他のトランザクションは、コミットされた変更のみを読み取ることができます。

この分離レベルは完璧に見え、ほとんどの論理シナリオに適合しますが、トランザクション分離レベルは「繰り返し不可」および「ファントム読み取り」の問題を引き起こします。

**再読み取り不可:**トランザクションで複数回読み取られた同じ行のデータを指しますが、結果は異なります。たとえば、トランザクションAが行aのデータを読み取り、トランザクションBがこの時点で行aのデータを変更してトランザクションをコミットすると、次にトランザクションAが行aのデータを読み取るときに、最初とは異なることがわかります。

**ファントムリーディング:**は、同じクエリ条件に従ってデータを取得するトランザクションを指しますが、複数回取得されるデータ結果は異なります。たとえば、トランザクションAは条件x = 0のデータを初めて取得し、5つのレコードを取得します。このとき、トランザクションBはx = 0のデータをテーブルに挿入してトランザクションを送信し、トランザクションAは条件x =を2回使用します。 0データを検索したところ、6件のレコードが取得されたことがわかりました。

では、なぜ繰り返し不可能な読み取りとファントム読み取りがREADCOMMITED分離レベルで発生するのでしょうか。

実際、繰り返し不可能な読み取りトランザクション分離レベルでも、前述のMVCC(マルチバージョン同時実行制御)メカニズムが使用されます。ただし、READ COMMITED分離レベルのMVCCメカニズムは、選択するたびに新しいシステムバージョン番号を生成するため、トランザクションの各選択操作は、データのコピーではなく異なるコピーを読み取ります。選択の合間に、他のトランザクションが読み取りデータを更新して送信すると、繰り返し不可能な読み取りとファントム読み取りが発生します。

次のように非反復可能読み取りの理由は次のとおりです。

REPEATABLE READ

トランザクション分離レベルREPEATABLEREADは、繰り返し可能読み取りとも呼ばれ、MySQLデータベースのデフォルトのトランザクション分離レベルです。このトランザクション分離レベルでは、トランザクション内の複数の読み取りの結果に一貫性があります。この分離レベルにより、ダーティ読み取りや繰り返し不可能な読み取りなどのクエリの問題を回避できます。

このトランザクション分離レベルの実現は、主に読み取り/書き込みロック+ MVCCメカニズムを使用することです。具体的な概略図は次のとおりです。

上の図に示すように、トランザクション分離レベルのMVCCメカニズムは、トランザクション内のクエリごとに新しいシステムバージョン番号を生成しないため、トランザクション内の複数のクエリ、データコピーは次のようになります。 1つなので、繰り返し不可能な読み取りの問題はありません。この分離レベルでのMVCCの詳細については、前のコンテンツを参照してください。

ただし、この分離レベルは繰り返し不可能な読み取りの問題を解決しますが、ファントム読み取りの問題は解決しないため、トランザクションAに条件付きクエリがある場合、別のトランザクションBがこの期間中に条件のデータを追加または削除することに注意してください。トランザクションをコミットしても、トランザクションAはファントム読み取りを生成します。したがって、MySQLを使用するときは、この問題に注意を払う必要があります。

シリアル化可能

この分離レベルは、読み取りおよび書き込み要求に排他ロックを追加するため、理解するのが最も簡単です。したがって、データの不整合が発生することはありません。つまり、パフォーマンスが高くないため、この分離レベルを使用するデータベースはほとんどありません。

4)、一貫性の実現

一貫性とは、主に、同時条件下でのロールバック、リカバリ、および分離によるデータベースデータの一貫性を指します。上記の原子性、永続性、および分離は、最終的に一貫性を実現するためのものです。

MySQLストレージエンジン

前のコンテンツでは、MySQLの同時実行制御とトランザクションのコンテンツについてそれぞれ説明しましたが、実際には、同時実行制御とトランザクションの特定の詳細は、MySqlストレージエンジンによって実装されます。MySQLの最も重要で特徴的な機能は、ストレージエンジンアーキテクチャです。データ処理とストレージを分離するこのアーキテクチャ設計により、ユーザーは、パフォーマンス、特性、およびその他の特定の要件に従って、対応するストレージエンジンを選択できます。

それでも、ほとんどの場合、MySQLデータベースを使用するときにInnoDBストレージエンジンが選択されますが、これは他のストレージエンジンの特性を正しく理解することを妨げるものではありません。次に、簡単な要約を次のように示します。

上記では、MySQLストレージエンジンの一般的な特性とそれらの一般的な適用可能なシナリオを簡単に要約しましたが、実際には、InnoDBストレージエンジンに加えて、インターネットビジネスで他の人を見かけることはめったにありません。ストレージエンジンの図。MySQLには特定のシナリオに対応するさまざまな組み込みストレージエンジンがありますが、それらのほとんどには対応する代替テクノロジーがあります。たとえば、ログアプリケーションにはElasticsearchがあり、データウェアハウスアプリケーションにはHive、HBaseなどの製品があります。メモリデータベースにはMangoDBがあります。 RedisなどのNoSQLデータ製品なので、MySQLで再生できるのはInnoDBだけです。

最後に書く

私の公開アカウント[風と波はコードと同じくらい静かです]に注目してください。Java関連の記事、学習資料が多数更新され、編集された資料もそこに配置されます。

文章が良いと思うなら、それと同じようにフォロワーを追加してください!注意して、迷子にならないで、更新を続けてください!

おすすめ

転載: blog.csdn.net/woshinidadaye_/article/details/109095545