RR および RC 分離レベルでのインデックスとロックのテスト スクリプトのサンプル コード

RR および RC 分離レベルでのインデックスとロックのテスト スクリプトのサンプル コード

基本概念

現在の読み取りとスナップショットの読み取り

MVCC では、読み取り操作はスナップショット読み取りと現在の読み取りの 2 つのカテゴリに分けられます。 スナップショットは、レコードの表示可能なバージョン (履歴バージョンの場合もあります) をロックせずに読み取ります。現在の読み取りではレコードの最新バージョンが読み取られ、返されたレコードは、トランザクションが終了する前にデータが最新バージョンであることを確認するためにロックされます。

スナップショット読み取り: 単純な選択操作はスナップショット読み取りであり、ロックされません (Serializable を除く)。

次のテーブルから * を選択します。

現在の読み取り: 挿入/更新/削除操作などの特殊な読み取り操作は現在の読み取りであり、ロックが必要です。

select * from table where ? lock in share mode;
更新のために、? のテーブルから * を選択します。
テーブルの値に挿入します();
テーブルセットを更新しますか? どこに?
テーブルから削除?

分離レベルとロック機構

  • コミットされていない読み取りはダーティ リードを引き起こすため、考慮されません。
  • 読み取りコミット (RC) 現在の読み取りでは、RC 分離レベルによって、読み取りレコードがロックされ (ギャップ ロック)、ファントム読み取りが発生する可能性があります。
  • 反復可能読み取り (RR) 現在の読み取りでは、RR 分離レベルにより、読み取られたレコードがロックされることが保証され (レコード ロック)、同時に読み取り範囲がロックされることが保証されます。クエリ条件を満たす新しいレコードは挿入できず (ギャップ ロック)、ファントム リード現象は発生しません。
  • Serializable のすべての読み取り操作は現在の読み取りに低下し、読み取りと書き込みの競合が発生するため、同時実行性が大幅に低下し、考慮されません。

テストスクリプト

-- 基本操作 --
--クエリトランザクション分離レベル。デフォルトはRRです。
'%isolation%' のような変数を表示します。

-- トランザクション分離レベルを RC に設定する
セッショントランザクション分離レベルをコミット読み取りに設定します。


-- データの初期化 --
始める;
ユーザーが存在する場合はテーブルを削除します。
テーブル `user` を作成します (
 `id` bigint(20) 符号なし NOT NULL AUTO_INCREMENT,
 `email` varchar(64) NOT NULL,
 `age` int(11) NOT NULL,
 `address` varchar(64) NOT NULL,
 主キー (`id`)、
 ユニークキー `uniq_email` (`email`)、
 キー `idx_age` (`age`)
);

ユーザー(メール、年齢、住所)に値(「[email protected]」、「18」、「address1」)を挿入します。
ユーザー(メール、年齢、住所)に値(「[email protected]」、「20」、「address2」)を挿入します。
ユーザー(メール、年齢、住所)に値(「[email protected]」、「20」、「address3」)を挿入します。

専念;
ユーザーから*を選択します。



-- 1. trx_idの例の開始;
INFORMATION_SCHEMA.INNODB_TRX から TRX_ID を選択し、TRX_MYSQL_THREAD_ID = CONNECTION_ID() を指定します。
ユーザーから*を選択します。
INFORMATION_SCHEMA.INNODB_TRX から TRX_ID を選択し、TRX_MYSQL_THREAD_ID = CONNECTION_ID() を指定します。
エンジン INNODB ステータスを表示します。
ユーザーを更新し、ID = 3 で age = 22 に設定します。
-- トランザクション ID を照会する
INFORMATION_SCHEMA.INNODB_TRX から TRX_ID を選択し、TRX_MYSQL_THREAD_ID = CONNECTION_ID() を指定します。
-- INNODB エンジンのステータス SHOW ENGINE INNODB STATUS;
専念;

-- 2. 繰り返し読み取りと繰り返し不可能な読み取りの例 -- セッション 1
セッショントランザクション分離レベルをコミット読み取りに設定します。
始める;
--セッション2
セッショントランザクション分離レベルを繰り返し読み取りに設定します。
始める;
--セッション1
ユーザーから*を選択します。
--セッション2
ユーザーから*を選択します。
--セッション3
始める;
ユーザー(メール、年齢、住所)に値(「[email protected]」、「30」、「address4」)を挿入します。
専念;
-- セッション 1 は RC モードなので、trx3 によって送信された新しいデータを読み取ることができます。反復不可能な読み取りを証明する場合は、挿入ではなく更新を使用する必要があります。
ユーザーから*を選択します。
専念;
-- ここではセッション 2 は RR なので、trx3 select * from user によって送信された新しいデータは読み取られません。
専念;

-- 3. スナップショット読み取りファントム読み取りの例 -- セッション 1
セッショントランザクション分離レベルを繰り返し読み取りに設定します。
始める;
-- ここではスナップショット read select * from user を使用します。
--セッション2
始める;
ユーザー(メール、年齢、住所)に値(「[email protected]」、「30」、「address4」)を挿入します。
専念;
ユーザーから*を選択します。
--セッション1
select * from user; -- test4@のデータはRRなのでここでは読み取れません
-- ここでファントム読み取りが発生します insert into user (email, age, address) values ​​("[email protected]", 30, "address4"); -- 電子メールの一意のインデックスの競合のため、挿入は失敗します commit;

-- 4. 電流読み取りファントム読み取りの例 -- RC
--セッション1
セッショントランザクション分離レベルをコミット読み取りに設定します。
始める;
-- ここでは、条件を満たす age = 20 のすべてのレコードがロックされます。RC なので、GAP ロックはありません。delete from user where age = 20;
ユーザーから*を選択します。
--セッション2
セッショントランザクション分離レベルをコミット読み取りに設定します。
始める;
-- trx1 には GAP ロックがないため、age=20 のレコードをユーザー (メール、年齢、住所) の値に挿入できます ("[email protected]", 20, "address4");
select * from user; -- 4 つのデータが見つかり、trx1 の削除されたデータを読み取ることができます。RC であるため、trx1 は送信されておらず、trx2 には影響しません。
専念;
--セッション1
select * from user; -- trx2 の新しく挿入されたデータを読み取ることができます。trx1 は現在読み取り中ですが、対応する次のキー ロックは追加されていないため、trx2 の新しいデータが挿入されコミットされることは妨げられません。

--RR
--セッション1
セッショントランザクション分離レベルを繰り返し読み取りに設定します。
始める;
年齢が 20 のユーザーから削除します。
ユーザーから*を選択します。
--セッション2
始める;
-- trx1 が age=20 付近に GAP ロックを追加するため、ブロックが発生します。 -- 一意でないインデックスの場合、まずインデックスを通じてクエリ条件を満たす最初のレコードを見つけ、そのレコードに X ロックを追加し、GAP に GAP ロックを追加してから、主キー クラスター化インデックスのレコードに X ロックを追加します。
-- 次に次のものを読んで繰り返します。条件を満たさない最初のレコードに到達するまで、この時点ではレコード X ロックを追加する必要はありませんが、GAP ロックは依然として必要であり、最終的に最後に戻ります。
ユーザー(メール、年齢、住所)に値(「[email protected]」、「20」、「address4」)を挿入します。
-- タイムアウトまで、ERROR 1205 (HY000): ロック待機タイムアウトを超えました。トランザクションを再起動してください。
-- この時点でクエリを実行すると、コミットされたレコードが 3 つ表示されます。
--セッション1
-- 現時点では 1 つのレコードのみが表示され、他の 2 つは削除されています。select * from user;
専念;

-- ユニークインデックス + RC
--セッション1
セッショントランザクション分離レベルをコミット読み取りに設定します。
始める;
email = "[email protected]" のユーザーから削除します。
--セッション2
始める;
-- trx1 は RC なので読み取ることができます
email = "[email protected]" のユーザーから * を選択します。
-- このレコードの age を更新しようとすると、タイムアウトまでブロックされます。これは、email が trx1 によってロックされている唯一のインデックスであり、対応する主キー インデックスもロックされるためです。 -- ここで操作される id=3 は、trx1 で操作された email の行レコードと同じであることに注意してください。update user set age = 40 where id = 3;
--セッション1
専念;
--セッション2
専念;

-- インデックスなし + RC
--セッション1
セッショントランザクション分離レベルをコミット読み取りに設定します。
始める;
-- アドレスフィールドにはインデックスがないため、Innodb はすべての行をロックし、MySQL サーバーが判断してロックを解除します。delete from user where address = "address3";
--セッション2
セッショントランザクション分離レベルをコミット読み取りに設定します。
始める;
-- この行はロックされていないため成功します (最初にロックされ、その後解放されます)
ユーザーを更新し、age = 10 とし、address = "address2" とします。
-- この行も、trx1 のステートメントによってロックされているためブロックされます。条件を満たすすべてのステートメントがロックされます。 update user set age = 10 where address = "address3";
--セッション1
専念;
--セッション2
専念;

-- 非一意インデックス + RR
--セッション1
セッショントランザクション分離レベルを繰り返し読み取りに設定します。
始める;
年齢が 20 のユーザーから削除します。
--セッション2
セッショントランザクション分離レベルを繰り返し読み取りに設定します。
始める;
-- age=20 のレコードが trx1 でロックされ、GAP ロックが追加されているため、18 がロック間隔に該当するため、ブロックが発生します。 insert into user (email, age, address) values ​​("[email protected]", 18, "address4");
--セッション1
専念;
--セッション2
専念;

-- インデックスなし RR
--セッション1
セッショントランザクション分離レベルを繰り返し読み取りに設定します。
始める;
-- インデックスがない場合、テーブル内のすべてのレコードがロックされ、主キー インデックスのすべてのギャップがロックされて、すべての同時更新操作が防止されます。delete from user where address = "address3";
--セッション2
セッショントランザクション分離レベルを繰り返し読み取りに設定します。
始める;
-- 主キーに GAP ロックが設定されているため、新しい挿入を正常に実行できず、ブロックされます。 insert into user (email, age, address) values ​​("[email protected]", 18, "address4");
--セッション1
専念;
--セッション2
専念;

-- 単純なデッドロックの例 -- セッション 1
始める;
ID = 1 のユーザーから削除します。
--セッション2
始める;
ID = 3 のユーザーから削除します。
--セッション1
ID = 3 のユーザーから削除します。
--セッション2
-- ここでMySQLはデッドロックが発生したと判断し、トランザクションを中断します。
-- エラー 1213 (40001): ロックを取得しようとしたときにデッドロックが見つかりました。トランザクションを再開してください。
ID = 1 のユーザーから削除します。
--セッション1
ロールバック;
--セッション2;
ロールバック;

-- 5. デッドロック挿入例 drop table if exists t1;
始める;
テーブルt1を作成(
 `id` bigint NULLではない auto_increment、
 主キー (`id`)
);
t1値に挿入する(1);
t1値に挿入する(5);
専念;
t1から*を選択します。
--セッション1
始める;
t1値に挿入する(2)
--セッション2
始める;
-- これにより、t1値への挿入がブロックされます(2)。
--セッション3
始める;
-- これにより、t1値への挿入がブロックされます(2)。
--セッション1;
-- この時点でロールバックが発生し、trx2 と trx3 が通知を受け取り、デッドロックが発生したため MySQL は自動的に 1 つの trx を中断します -- エラー 1213 (40001): ロックを取得しようとしたときにデッドロックが見つかりました。トランザクションを再起動してください
ロールバック;
--セッション2;
ロールバック;
--セッション3;
ロールバック;

要約する

上記はこの記事の全内容です。この記事の内容が皆さんの勉強や仕事に一定の参考学習価値を持つことを願っています。ご質問があれば、メッセージを残してコミュニケーションしてください。123WORDPRESS.COM を応援していただきありがとうございます。

以下もご興味があるかもしれません:
  • MySQLの4つの分離レベルについての深い理解
  • Innodb トランザクション分離レベルと MySQL のロックの関係に関するチュートリアル
  • MySQL データベースのトランザクション分離レベル (トランザクション分離レベル) の概要
  • MYSQL REPEATABLE-READ 分離レベルの簡単な分析
  • MySQL の 4 つのトランザクション分離レベルの詳細な説明と比較
  • MySQL トランザクション分離とパフォーマンスへの影響の詳細な分析
  • MySQL の 4 つのトランザクション分離レベルの詳細な説明

<<:  オペレーターが知っておくべき 18 個の Nginx プロキシ キャッシュ構成のヒント (どれを知っていますか?)

>>:  antd ツリーと親子コンポーネント間の値転送問題について (React のまとめ)

推薦する

Tomcat Nativeを使用してTomcat IO効率を向上させる方法の詳細な説明

目次導入Tomcatへの接続方法APR と Tomcat ネイティブtomcat で APR を使用...

MySQL からエクスポートされた scv ファイル内の文字化けやジャンプ行の問題をすばやく解決します

仕事上の理由により、完全なオンライン化(​​つまり、すべてのデータがオンラインで完了し、インポートや...

MySQLは複数テーブル関連統計(サブクエリ統計)の例を実装します

この記事では、例を使用して、MySQL で複数テーブルの関連統計を実装する方法について説明します。ご...

JavaScript ES6 分割演算子の理解と応用

目次序文脱構築記号の役割使い方分割割り当ての適用アプリケーションの簡単な紹介JSONデータを抽出する...

mysql 8.0.19 winx64.zip インストール チュートリアル

この記事は参考までにmysql 8.0.19 winx64.zipのインストールチュートリアルを記録...

浮遊する雲のアニメーションを実現するCSS3

操作効果 html <ヘッド> <メタ文字セット='UTF-8'&...

Windows で mysql 8.0.12 をインストールするための詳細なチュートリアル

この記事では、MySQL 8.0.12のインストール方法に関する詳細なチュートリアルを参考までに紹介...

モバイルフロントエンド適応ソリューション(概要)

ネットで検索してみたところ、多くの面接でモバイル適応方法について質問されることが分かりました。最近い...

Ubuntu 向け VMware Tools のインストールと構成のチュートリアル

以前、ブロガーは VMware 仮想マシンに Ubuntu システムをインストールしました。まだイン...

Linuxシステムでノードプロセスを実行しているが、プロセスを強制終了できない問題を解決します

まず、Linux システムで実行されているノード プロセスはプロセスを強制終了できないことを紹介しま...

ノード スキャフォールディングを使用してトークン検証を実装するサーバーを構築する方法

コンテンツスキャフォールディングを使用してノードプロジェクトを素早く構築するデータベースとやり取りす...

Centos7 で yum を使用して Ceph 分散ストレージをインストールするチュートリアル

目次序文yumソース、epelソースを設定するCephソースの設定Cephとそのコンポーネントをイン...

CentOS 6.8 に MySQL 8.0.18 をインストールするチュートリアルの簡単な分析 (RPM 方式)

今日は、CentOS 6.8 サーバーに MySQL 8.0.18 をインストールする方法を記録しま...

Javascriptの基本ループの詳しい説明

目次サイクルのために入室のためのその間しながら行うループから抜け出す要約するサイクルのためにループは...

WeChat アプレットのシンプルなログイン ページの実装 (ソース コード付き)

目次1. 上の写真2. ユーザーが存在しない3. コードをアップロードする1. 上の写真 2. ユー...