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

推薦する

MySQL 8.0 をインストールした後、初めてログインするときにパスワードを変更する問題を解決する

MySQL 8.0.16で初回ログイン時のパスワードを変更する方法を紹介します。 MySQLデータベ...

Linux 継続的インテグレーションで Maven を自動的にインストールする方法

Mavenパッケージを解凍する tar xf apache-maven-3.5.4-bin.tar....

ネイティブ JavaScript でショッピングカートを実装する

この記事では、ショッピングカートを実装するためのJavaScriptの具体的なコードを参考までに紹介...

入力のsize属性とmaxlength属性の違い

最近、プロジェクトで input size 属性と maxlength 属性を使用しました。以前は、...

MySQL 接続例外とエラー 10061 の解決方法

MySQL は、スウェーデンの会社 MySQL AB によって開発されたリレーショナル データベース...

pagodaを使用してionCube拡張機能をインストールする方法

1. まずパゴダを設置するインストール要件: Python バージョン: 2.6/2.7 (Pago...

Windows が MySQL サービスを開始できず、エラー 1067 を報告する場合の解決策

突然、MySQLにログインすると、アクセスが拒否されたか、データベースに接続できないと表示されました...

EDMをHTMLで記述する際の注意点まとめ(メール送信時の一般的な注意点)

フォーマットエンコーディング1. ページの幅は600~800px、長さは1024px以内に設定してく...

Vue ルーター vue-router 詳細説明ガイド

中国語ドキュメント: https://router.vuejs.org/zh/ Vue Router...

画像マーキー効果を実現するネイティブJS

今日は、ネイティブ JS で実装された画像マーキー効果を紹介します。効果は次のとおりです。 実装され...

MySQL Innodb ストレージ構造と Null 値の保存の詳細な説明

背景:テーブルスペース: すべての INNODB データはテーブルスペース (共有テーブルスペース)...

React+Typescriptはカウントダウンフックメソッドを実装します

まず、setIntervalはフックとしてカプセル化されます👇 'react' から...

MySQL の最適化: サブクエリの代わりに結合を使用する

サブクエリの代わりにJOINを使用するMySQL はバージョン 4.1 以降で SQL サブクエリを...

GIFアニメーション効果を模倣した自動ビデオ再生を実現するWeChatアプレットの例

需要背景:ミニプログラムページに GIF ダイナミック画像を挿入しますが、GIF 画像は通常サイズが...

Linux で誤って削除したメッセージ ファイルを復元する方法

プロセスで使用されていて、誤って削除されたファイルがある場合、それらを回復することができます。プロセ...