インタビュアー:MVCCはどのように達成されますか?

ここに画像の説明を挿入

MVCCは何をしますか?

mvccは、指定されたバージョンの履歴レコードを読み取り、読み取りレコード値がトランザクションの分離レベルを満たしていることを確認し、ロックせずに読み取りと書き込みの競合を解決することにより、マルチバージョン同時実行制御です。

mvccに慣れていない方は、この文章を読んだ後、少し戸惑うかもしれませんが、大丈夫です。この記事を読むと、この文章を理解できます。

InnoDBストレージエンジンを使用するテーブルの場合、クラスター化インデックスレコードには、次の2つの必要な非表示列が含まれます

trx_id:トランザクションがクラスター化インデックスレコードを変更するたびに、トランザクションのトランザクションIDがtrx_id非表示列に割り当てられます。

roll_pointer:クラスター化インデックスレコードが変更されるたびに、古いバージョンが元に戻すログに書き込まれます。この非表示の列は、レコードを変更する前に情報を見つけるためのポインターに相当します。

レコードの名前をDiaoChanからWangZhaojun、Xi Shiに変更すると、次のレコードが作成され、複数のレコードがバージョンチェーンを形成し
ここに画像の説明を挿入
ますまず、次のコンテンツが混乱しないように、分離レベルの概念を確認してください。 。

√はそれが起こることを意味し、×はそれが起こらないことを意味します

分離レベル ダーティリード 繰り返し不可 ファントムリーディング
コミットされていない読み取り(コミットされていない読み取り)
コミットされた読み取り ××
繰り返し可能な読み取り(繰り返し可能な読み取り) ×× ××
シリアライズ可能(シリアライズ可能) ×× ×× ××

提出されたものを読む

次のテーブルを作成します

CREATE TABLE `account` (
  `id` int(2) NOT NULL AUTO_INCREMENT,
  `name` varchar(10) DEFAULT NULL,
  `balance` int(3) DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;

表のデータは次のとおりです。送信された読み取りに分離レベルを設定します
ここに画像の説明を挿入

時間 クライアントA(タブA) クライアントB(タブB)
T1 セッショントランザクション分離レベルの読み取りコミットの設定;
トランザクションの開始;
id = 2のアカウントから*を選択;
クエリバランスの出力は0
T2 セッショントランザクション分離レベルの読み取りコミットを設定します。
トランザクションを開始します。
アカウントセットの残高を更新=残高+1000ここで、id = 2;
select * from account where id = 2;
コミット;
查询余额輸出出1000
T3 select * from account where id = 2;
commit;
check balance output 1000

繰り返し不可の読み取りとは、トランザクション1でデータの一部が読み取られ、トランザクション1が終了していない場合、トランザクション2もデータにアクセスし、データを変更して送信したことを意味します。その直後、トランザクション1はこのデータを再度読み取ります。トランザクション2の変更により、トランザクション1で2回読み取られたデータが異なる場合があるため、繰り返し不可の読み取りと呼ばれます。

繰り返し可能

表のデータは次のとおりです。分離レベルを繰り返し可能な読み取りに設定します
ここに画像の説明を挿入

時間 クライアントA(タブA) クライアントB(タブB)
T1 セッショントランザクション分離レベルの繰り返し読み取りの設定;
トランザクションの開始;
id = 2のアカウントから*を選択;
クエリバランスの出力は0
T2 セッショントランザクション分離レベルの繰り返し可能な読み取りを設定します。
トランザクションを開始します。
アカウントセットの残高を更新=残高+1000ここで、id = 2;
select * from account where id = 2;
コミット;
查询余额輸出出1000
T3 select * from account where id = 2;
commit;
check balance output 0

この例と上記の例のT3期間の出力を注意深く見て、繰り返し可能な読み取り値が何であるかを理解しますか?現在のセッションの分離レベルを繰り返し可能な読み取りに設定すると、現在のセッションを繰り返し読み取ることができます。つまり、他のトランザクションがコミットされているかどうかに関係なく、各読み取りの結果セットは同じです。

この実験を終えたとき、私は盲目でしたが、MySQLはこれらの2つの分離レベルをどのようにサポートしていますか?見下ろそう

MVCCはどのように実装されていますか?

バージョンチェーンのどのバージョンが現在のトランザクションに表示されるかを判断するために、MySQLはReadViewの概念を設計しました4つの重要な内容は次のとおりです

m_ids:ReadViewが生成されると、現在のシステムのアクティブなトランザクションIDリスト
min_trx_id:ReadViewが生成されると、システムで現在アクティブな最小のトランザクションID、
つまりm_idsの最小値max_trx_id:ReadViewが生成されるとシステムは、次のトランザクションのトランザクションID値に割り当てるべき
creator_trx_id ReadViewを生成したトランザクションのトランザクションID:

テーブル内のレコードに変更が加えられたとき、挿入、削除、および更新ステートメントが実行されると、一意のトランザクションIDがトランザクションに割り当てられます。それ以外の場合、トランザクションのトランザクションID値はデフォルトで0です。

max_trx_idはm_idsの最大値ではなく、トランザクションIDは段階的に割り当てられます。たとえば、トランザクションID 1、2、および3の3つのトランザクションがあり、トランザクションID 3のトランザクションが送信されます。新しいトランザクションがReadViewを生成する場合、m_idsの値には1と2が含まれ、min_trx_idの値は次のようになります。 1.、max_trx_idの値は4です

mvccがバージョンチェーン内のどのバージョンを現在のトランザクションに表示するかを決定するプロセスは
ここに画像の説明を挿入
次のとおりです。

  1. アクセスされたバージョンのtrx_id = creator_idの場合、現在のトランザクションが自身の変更されたレコードにアクセスしていることを意味するため、現在のトランザクションからこのバージョンにアクセスできます。
  2. アクセスされたバージョンのtrx_id <min_trx_idの場合、現在のトランザクションがReadViewを生成する前に、このバージョンを生成したトランザクションがコミットされていることを示しているため、現在のトランザクションからこのバージョンにアクセスできます。
  3. アクセスされたバージョンのtrx_id> = max_trx_idは、現在のトランザクションがReadViewを生成した後に、このバージョンを生成したトランザクションが開始され、現在のトランザクションがこのバージョンにアクセスできないことを示します。
  4. アクセスされたバージョンのtrx_idはm_idsリストにありますか?
    4.1はい、ReadViewが作成されたとき、バージョンはまだアクティブであり、アクセスできません。バージョンチェーンに従ってデータの次のバージョンを見つけ、上記の手順を実行して可視性を判断します。最後のバージョンが表示されない場合は、レコードが現在のトランザクションから完全に非表示になっていることを意味します
    。4.2いいえ、ReadViewの場合が作成され、このバージョンを生成したトランザクションが送信されました。このバージョンにアクセスできます

写真を見て少し混乱していますか?例をあげる時間

次のテーブルを作成します

CREATE TABLE `girl` (
  `id` int(11) NOT NULL,
  `name` varchar(255),
  `age` int(11),
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

コミット済みを読む

データが読み取られる前にReadViewが生成されるたびに、読み取りがコミットされました(読み取りが送信されました)。

ここに画像の説明を挿入
以下は3つのトランザクションの実行プロセスです。行は時点を表し、
ここに画像の説明を挿入
この時点で5つの実行プロセスを分析します。

  1. システムには、それぞれID100と200の2つのトランザクションが実行されています。
  2. readViewは、selectステートメントが実行されると生成されます。mids= [100,200]、min_trx_id = 100、max_trx_id = 201、creator_trx_id = 0(selectトランザクションは変更されず、トランザクションIDはデフォルトで0になります)
  3. 最新バージョンの名前はXiShiとしてリストされており、このバージョンのtrx_id値は100です。midsリストでは、可視性の要件を満たしていません。roll_pointerに従って次のバージョンにスキップしてください。
  4. 次のバージョンの名前はWangZhaojunです。このバージョンのtrx_id値は100ですが、これもmidsリストに含まれているため、要件を満たしていません。次のバージョンに進みます。
  5. 次のバージョンの名前はDiaochanとしてリストされ、このバージョンのtrx_id値は10であり、min_trx_id未満であるため、返される姓はDiaochanです。

ここに画像の説明を挿入

この時点でのselectの実行プロセスを分析してみましょう8。

  1. 実行中のシステムにトランザクションIDが200のトランザクションがあります(トランザクションIDが100のトランザクションがコミットされています)
  2. selectステートメントの実行時にReadViewを生成します、mids = [200]、min_trx_id = 200、max_trx_id = 201、creator_trx_id = 0
  3. 最新バージョンの名前はYangYuhuanとしてリストされており、このバージョンのtrx_id値は200です。midsリストでは、可視性の要件を満たしていません。roll_pointerに従って次のバージョンにスキップしてください。
  4. 次のバージョンの名前はXiTzuとしてリストされ、このバージョンのtrx_id値は100であり、min_trx_id未満であるため、返される姓はXiTzuです。

トランザクションIDが200のトランザクションが送信されると、クエリによって取得された名前はYangYuhuanとしてリストされます。

繰り返し読み取り

繰り返し読み取り(繰り返し読み取り)、データを初めて読み取ると、ReadViewが生成されます。
ここに画像の説明を挿入
繰り返し読み取り。ReadViewは、データを初めて読み取るときにのみ生成されるため、毎回同じバージョンが読み取られます。名前の値私はいつも貂蝉です。特定のプロセスは上記の2回説明されています。ここでは説明を繰り返しません。自分で分析してください。

リファレンスブログ

「MySQLのしくみ:基本からMySQLを理解する」
[1] https://blog.csdn.net/qq_35190492/article/details/106915564

おすすめ

転載: blog.csdn.net/zzti_erlie/article/details/110454543