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 のまとめ)

推薦する

Linux サーバー上の hosts ファイル構成の詳細な説明

Linux サーバーのホスト ファイルの構成hosts ファイルは、Linux システム内の IP ...

登録フォームのデザインルール

随分前に「Patterns for Sign Up & Ramp Up」を読み終えました。今...

MySQLデータベーストリガーの詳細な説明

目次1 はじめに2 トリガーの紹介3 トリガーを作成する4 トリガーを表示5. トリガーの削除6 結...

Dockerコンテナ監視の原理とcAdvisorのインストールおよび使用方法

本番環境におけるコンテナの稼働状況を監視することは非常に重要です。監視を通じて、コンテナの稼働状況を...

mysql 基本操作文コマンドの詳細な説明

1. MySQLに接続するフォーマット: mysql -h ホストアドレス -u ユーザー名 -p ...

MySQL学習データベース操作DML初心者向け詳細解説

目次1. ステートメントを挿入する1.1 行を挿入する1.2 複数行を挿入する1.3 クエリステート...

Docker で Spring-boot プロジェクトをデプロイするためのサンプル コード

1. 基本的な Spring-boot クイックスタート1.1 クイックスタート pom.xml は...

JavaScript で文字列を数値に変換する方法

目次1.parseInt(文字列、基数) 2. 数値() 3.parseFloat()主なメソッドは...

HTML テーブルタグチュートリアル (32): セルの水平方向の配置属性 ALIGN

水平方向では、セルの配置を左、中央、右に設定できます。基本的な構文<TD ALIGN=&quo...

テキストエリアの disabled 属性と readonly 属性の具体的な使用法

障害者の定義と使用法disabled 属性はブール属性です。 disabled 属性は、テキスト領域...

CSS 属性値正規マッチングセレクターの使い方 (ヒント)

属性値の正規一致セレクターには 3 つの種類があります。 [属性^="値"] [...

HTMLで境界線を設定する3つの方法の詳細な説明

HTML で境界線を設定する 3 つの方法 境界線の幅: 1px 2px 2px; 境界線のスタイル...

MySQL 5.7 のスロークエリログの時間がシステム時間より 8 時間遅れている理由の詳細な説明

遅いクエリをチェックすると、時間が正しくなく、システム時間とちょうど 8 時間異なっていることがわか...

div の特定の実装は自動的に折り返されず、HTML で折り返されないよう強制されます。

1. 改行なしを実現するには<nobr>タグを使用するコードをコピーコードは次のとおりで...

js の通常形式の日付と時刻に 0 を自動的に追加する 2 つのソリューション

目次背景解決策1アイデア:コード:解決策2アイデア:要約する参照する背景日付と時間をフォーマットする...