MySQL InnoDB ロック メカニズムの詳細な例

MySQL InnoDB ロック メカニズムの詳細な例

1. InnoDBのロック機構

InnoDB ストレージ エンジンは、行レベルのロックとトランザクション処理をサポートします。トランザクションは、SQL ステートメントのグループで構成される論理処理単位です。その ACID 特性は次のとおりです。

  • 原子性: トランザクションは原子かつ不可分であり、一緒に実行されるか、まったく実行されないかのいずれかです。
  • 一貫性: データはトランザクションの開始時と終了時に一貫した状態を維持します。
  • 分離: トランザクションの開始時と終了時に、トランザクションは特定の分離特性を維持し、トランザクションが外部の同時データ操作の影響を受けないようにします。
  • 耐久性: トランザクションが完了すると、データはデータベースに保持されます。

同時トランザクションはデータベース リソースの使用率を改善し、データベースのトランザクション スループットを向上できますが、同時トランザクションには主に次のような問題もあります。

  • 更新の損失: 2 つのトランザクションが同じデータを更新しますが、2 番目のトランザクションが失敗して途中で終了し、両方の変更が無効になります。この時点ではデータベースはロック操作を実行しないため、同時実行中のトランザクションは分離されません。 (この問題は現代のデータベースではもう存在しません)
  • ダーティ リード: トランザクションがデータ行を読み取りますが、別のトランザクションがすでにこのデータ行を更新しています。これは非常に危険であり、すべての操作がロールバックされる可能性があります。
  • 反復不可能な読み取り: トランザクションはデータの行を 2 回 (またはそれ以上) 読み取りますが、異なる結果が得られます。2 回の読み取り中に、別のトランザクションがデータを変更した可能性があります。
  • ファントム リード: トランザクションは操作中に 2 つのクエリを実行し、2 番目のクエリ結果には最初のクエリには表示されなかったデータが含まれます。ファントム リードの主な原因は、2 つのクエリ プロセス中に別のトランザクションが新しいデータを挿入することです。

データベースの同時実行における「更新損失」は通常完全に回避されるはずですが、更新データの損失を防ぐことはデータベースのトランザクション制御だけでは解決できません。アプリケーションは更新するデータに必要なロックを追加する必要があります。上記のデータベースの問題は、データベースが特定のトランザクション分離メカニズムを提供することで解決する必要があります。同時データベース トランザクションによって発生する問題を回避するために、標準 SQL 仕様では 4 つのトランザクション分離レベルが定義されています。分離レベルによってトランザクションの処理方法が異なります。

データベース分離レベルの比較

分離レベルデータの一貫性の読み取りダーティリード繰り返し不可能な読み取りファントムリード
コミットされていない読み取り
(コミットされていないものを読む)
最も低いレベルでは、物理的に損傷したデータは読み取られないことのみが保証されますはいはいはい
コミットされた読み取り
(コミットされた読み取り)
ステートメントレベルいいえはいはい
繰り返し読み取り
(繰り返し読み取り)
トランザクションレベルいいえいいえはい
シリアル化可能
(シリアル化可能)
最高レベル、取引レベルいいえいいえいいえ

InnoDB ストレージ エンジンは、共有ロック (S)、排他ロック (X)、意図的共有ロック (IS)、および意図的排他ロック (IX) の 4 種類の行ロックを実装します。

  • 共有ロック: 誰でも読み取りはできますが、変更はできません。排他的共有ロックを保持している場合、そのうちの 1 人だけが変更できます。
  • 排他ロック: 変更したいが、変更も読み取りもできない(ただし、MVCC スナップショットでは読み取り可能)

意図ロックを理解する

意図ロックは行レベルの S ロックおよび X ロックとは競合しませんが、テーブルレベルの S ロックおよび X ロックとのみ競合します。

意図ロックはすべての行ロックのトラバースを回避するためのものである

次の例を考えてみましょう。

トランザクション A はテーブル内の行をロックし、読み取り可能にしますが書き込み不可にします。

その後、トランザクション B はテーブル全体の書き込みロックを申請します。

トランザクション B が成功した場合、理論上はテーブル内の任意の行を変更でき、これは A が保持している行ロックと競合します。

データベースはこの競合を回避する必要があります。つまり、A が行ロックを解除するまで、B のアプリケーションをブロックする必要があります。

データベースはこの競合をどのように判断するのでしょうか?

ステップ1: テーブルが他のトランザクションによってロックされているかどうかを確認する

ステップ 2: テーブル内の各行が行ロックによってロックされているかどうかを判断します。

ステップ 2 に注意してください。この判断方法は、テーブル全体を走査する必要があるため、あまり効率的ではありません。

つまり、意図ロックがあるのです。

意図ロックが存在する場合、トランザクション A は最初にテーブルに対して意図共有ロックを適用し、成功した場合は行に対して行ロックを適用する必要があります。

意図ロックの場合、上記の判定は次のように変更される。

ステップ1: 変更なし

ステップ 2: テーブルに意図的な共有ロックがあることが判明しました。これは、テーブル内の一部の行が共有行ロックによってロックされていることを意味します。したがって、トランザクション B によるテーブルへの書き込みロックの適用はブロックされます。

1.1 インデックスを介してデータを取得し、共有ロック、行ロックを適用します(インデックスを介さない場合は、テーブルロックが使用されます)

1.1 インデックスを介してデータを取得し、共有ロックと行ロックを設定する セッションA セッションB
mysql> 自動コミットを 0 に設定します。mysql> 自動コミットを 0 に設定します。
クエリは正常、影響を受けた行は 0 行 (0.02 秒) クエリは正常、影響を受けた行は 0 行 (0.02 秒)
mysql> テストから * を選択します。mysql> テストから * を選択します。
--------------------------------------------------------------------------------
+----+-------+-------+-------+ +----+--------+-------+-------+              
| id | 名前 | お金 | レベル | | id | 名前 | お金 | レベル |
+----+-------+-------+-------+ +----+--------+-------+-------+
| 1 | トム | 100 | 1 | | 1 | トム | 100 | 1 |
| 2 | ジャック | 200 | 2 | | 2 | ジャック | 200 | 2 |
| 3 | ルーカス | 300 | 3 | | 3 | ルーカス | 300 | 3 |
+----+-------+-------+-------+ +----+--------+-------+-------+
3 行セット (0.00 秒) 3 行セット (0.00 秒)
--------------------------------------------------------------------------------
主キーインデックスの共有ロック、他のトランザクションも共有ロックを取得できます。mysql> select * from test where         
id=1 共有モードでロックします。
+----+------+-------+-------+
| ID | 名前 | お金 | レベル |
+----+------+-------+-------+
| 1 | トム | 100 | 1 |
+----+------+-------+-------+
セット内の1行(0.01秒)
--------------------------------------------------------------------------------
                        トランザクションBは共有ロックの追加も続行できますmysql> select * from test where         
                        id=1 共有モードでロックします。
                        +----+------+-------+-------+
                        | ID | 名前 | お金 | レベル |
                        +----+------+-------+-------+
                        | 1 | トム | 100 | 1 |
                        +----+------+-------+-------+
                        セット内の1行(0.01秒)
                        ただし、トランザクション A は共有ロックも追加するため、更新できません。mysql> update test set level=11 where id=1;
                        エラー 1205 (HY000): ロック待機タイムアウトを超えました。
                        トランザクションを再開してみてください
                        
                        もっと:
                        更新時に id=1 のテストから select *from 排他ロックを追加できません。
                        エラー 1205 (HY000): ロック待機タイムアウトを超えました。
                        トランザクションを再開してみてください
                        
                        ロック解除されたものを更新できます。たとえば、mysql> update test set level=11 where id=2;
                        クエリは正常、1 行が影響を受けました (0.00 秒)
                        一致した行: 1 変更された行: 1 警告: 0
--------------------------------------------------------------------------------
トランザクション B が共有ロックを追加するため、トランザクション A も更新できません。mysql> update test set level=11 where id=1;
エラー 1205 (HY000): ロック待機タイムアウトを超えました
ded; トランザクションを再開してください
--------------------------------------------------------------------------------
                        いずれかが共有ロックを解放すると、共有ロックを排他的に保持しているトランザクションは更新できます。mysql> commit;
                        クエリは正常、影響を受けた行は 0 行 (0.00 秒)
--------------------------------------------------------------------------------
トランザクション B はロックを解除し、トランザクション A は排他的所有権を持ち、更新できるようになります。mysql> update test set level=11 where id=1;
クエリは正常、1 行が影響を受けました (0.00 秒)
一致した行: 1 変更された行: 1 警告: 0

1.2 インデックスを介してデータを取得し、排他ロックと行ロックを設定する

1.2 インデックスを介してデータを取得し、排他ロックと行ロックを設定する セッションA セッションB
mysql> 自動コミットを 0 に設定します。mysql> 自動コミットを 0 に設定します。
クエリは正常、影響を受けた行は 0 行 (0.02 秒) クエリは正常、影響を受けた行は 0 行 (0.02 秒)
mysql> テストから * を選択します。mysql> テストから * を選択します。
--------------------------------------------------------------------------------
+----+-------+-------+-------+ +----+--------+-------+-------+              
| id | 名前 | お金 | レベル | | id | 名前 | お金 | レベル |
+----+-------+-------+-------+ +----+--------+-------+-------+
| 1 | トム | 100 | 1 | | 1 | トム | 100 | 1 |
| 2 | ジャック | 200 | 2 | | 2 | ジャック | 200 | 2 |
| 3 | ルーカス | 300 | 3 | | 3 | ルーカス | 300 | 3 |
+----+-------+-------+-------+ +----+--------+-------+-------+
3 行セット (0.00 秒) 3 行セット (0.00 秒)
--------------------------------------------------------------------------------
主キーインデックスの排他ロック、他のトランザクションも共有ロックを取得できます。mysql> select * from test where
更新の場合はid=1。
+----+------+-------+-------+
| ID | 名前 | お金 | レベル |
+----+------+-------+-------+
| 1 | トム | 100 | 1 |
+----+------+-------+-------+
セット内の1行(0.01秒)
--------------------------------------------------------------------------------
                        トランザクション B は排他ロックの取得を続行できず、mysql> select *from test where id=1 for update; を待機します。
                        エラー 1205 (HY000): ロック待機タイムアウトを超えました。
                        トランザクションを再開してみてください
                        
                        もっと:
                        更新によって排他ロックも設定されるため、更新もできません。mysql> update test set level=2 where id=1;
                        エラー 1205 (HY000): ロック待機タイムアウトを超えました。
                        トランザクションを再開してみてください
                        
                        mysql> select * from test where level=1 lock in share mode;
                        エラー 1205 (HY000): ロック待機タイムアウトを超えました。
                        トランザクションを再開してみてください
--------------------------------------------------------------------------------
トランザクション A は更新できます。mysql> update test set level=11 where id=1;
クエリは正常、1 行が影響を受けました (0.08 秒)
一致した行: 1 変更された行: 1 警告: 0
--------------------------------------------------------------------------------
排他ロックを解除します。mysql> commit;
クエリは正常、影響を受けた行は 0 行 (0.00 秒)
--------------------------------------------------------------------------------
                        トランザクション A はロックを解除し、トランザクション B は排他ロックを追加できます。mysql> select * from test where id=1 for update;
                        +----+------+-------+-------+
                        | ID | 名前 | お金 | レベル |
                        +----+------+-------+-------+
                        | 1 | トム | 100 | 1 |
                        +----+------+-------+-------+
                        セット内の 1 行 (0.00 秒)

1.3 インデックスを介してデータを更新し、排他ロックと行ロックも設定する

更新、挿入、削除ステートメントでは、排他ロックが自動的に追加されます。

1.3 インデックスを介してデータを更新し、排他ロック、行ロックも設定する セッションA セッションB
mysql> 自動コミットを 0 に設定します。mysql> 自動コミットを 0 に設定します。
クエリは正常、影響を受けた行は 0 行 (0.02 秒) クエリは正常、影響を受けた行は 0 行 (0.02 秒)
mysql> テストから * を選択します。mysql> テストから * を選択します。
--------------------------------------------------------------------------------
+----+-------+-------+-------+ +----+--------+-------+-------+              
| id | 名前 | お金 | レベル | | id | 名前 | お金 | レベル |
+----+-------+-------+-------+ +----+--------+-------+-------+
| 1 | トム | 100 | 1 | | 1 | トム | 100 | 1 |
| 2 | ジャック | 200 | 2 | | 2 | ジャック | 200 | 2 |
| 3 | ルーカス | 300 | 3 | | 3 | ルーカス | 300 | 3 |
+----+-------+-------+-------+ +----+--------+-------+-------+
3 行セット (0.00 秒) 3 行セット (0.00 秒)
--------------------------------------------------------------------------------
id=1 の行を更新すると、その行に排他ロックが設定され、他のトランザクションはその行を更新できなくなります。mysql> update test set level=11 where id=1;
クエリは正常、1 行が影響を受けました (0.00 秒)
一致した行: 1 変更された行: 1 警告: 0
--------------------------------------------------------------------------------
                        トランザクション B は id=1 の行を更新できないため、mysql> update test set level=21 where id=1; を待機します。
                        エラー 1205 (HY000): ロック待機タイムアウトを超えました。
                        トランザクションを再開してみてください
                        
                        もっと:
                        排他ロックを設定することはできません。mysql> select *from test where id=1 for update;
                        エラー 1205 (HY000): ロック待機タイムアウトを超えました。
                        トランザクションを再開してみてください
                        
                        mysql> select * from test where level=1 lock in share mode;
                        エラー 1205 (HY000): ロック待機タイムアウトを超えました。
                        トランザクションを再開してみてください
--------------------------------------------------------------------------------
排他ロックを解除します。mysql> commit;
クエリは正常、影響を受けた行は 0 行 (0.00 秒)
--------------------------------------------------------------------------------
                        トランザクション A はロックを解除し、トランザクション B は排他ロックを追加できます。mysql> select * from test where id=1 for update;
                        +----+------+-------+-------+
                        | ID | 名前 | お金 | レベル |
                        +----+------+-------+-------+
                        | 1 | トム | 100 | 11|
                        +----+------+-------+-------+
                        セット内の 1 行 (0.00 秒)

2.1 ダーティリード

//ダーティリード //2.1 ダーティリード セッションA セッションB
mysql> 自動コミットを 0 に設定します。mysql> 自動コミットを 0 に設定します。
クエリは正常、影響を受けた行は 0 行 (0.02 秒) クエリは正常、影響を受けた行は 0 行 (0.02 秒)
セッション トランザクション分離を設定します。セッション トランザクション分離レベルを設定します。コミットされていない読み取りです。
レベル読み取りはコミットされていません。クエリは正常、0 行が影響を受けました (0.00 秒)
クエリは正常、影響を受けた行は 0 行 (0.00 秒)      
mysql> テストから * を選択します。mysql> テストから * を選択します。
--------------------------------------------------------------------------------
+----+-------+-------+-------+ +----+--------+-------+-------+              
| id | 名前 | お金 | レベル | | id | 名前 | お金 | レベル |
+----+-------+-------+-------+ +----+--------+-------+-------+
| 1 | トム | 100 | 1 | | 1 | トム | 100 | 1 |
| 2 | ジャック | 200 | 2 | | 2 | ジャック | 200 | 2 |
| 3 | ルーカス | 300 | 3 | | 3 | ルーカス | 300 | 3 |
+----+-------+-------+-------+ +----+--------+-------+-------+
3 行セット (0.00 秒) 3 行セット (0.00 秒)
--------------------------------------------------------------------------------
                        mysql> テスト セット レベル = 100 を更新します (ID = 1)。
                        クエリは正常、1 行が影響を受けました (0.00 秒)
                        一致した行: 1 変更された行: 1 警告: 0
--------------------------------------------------------------------------------
//ダーティ readmysql> select *from test where id=1;
+----+------+-------+-------+
| ID | 名前 | お金 | レベル |
+----+------+-------+-------+
| 1 | トム | 100 | 100 |
+----+------+-------+-------+
セット内の 1 行 (0.00 秒)
--------------------------------------------------------------------------------
                        ロールバック;
                        クエリは正常、影響を受けた行は 0 行 (0.01 秒)
                        
                        mysql> id=1 のテストから * を選択します。
                        +----+------+-------+-------+
                        | ID | 名前 | お金 | レベル |
                        +----+------+-------+-------+
                        | 1 | トム | 100 | 1 |
                        +----+------+-------+-------+
                        セット内の 1 行 (0.00 秒)

2.2 繰り返し不可能な読み取り

2.2 繰り返し不可能な読み取り // ダーティ読み取り セッションA セッションB
mysql> 自動コミットを 0 に設定します。mysql> 自動コミットを 0 に設定します。
クエリは正常、影響を受けた行は 0 行 (0.02 秒) クエリは正常、影響を受けた行は 0 行 (0.02 秒)
セッション トランザクション分離を設定します。セッション トランザクション分離レベルを設定します。コミットされていない読み取りです。
レベル読み取りはコミットされていません。クエリは正常、0 行が影響を受けました (0.00 秒)
クエリは正常、影響を受けた行は 0 行 (0.00 秒)      
mysql> テストから * を選択します。mysql> テストから * を選択します。
--------------------------------------------------------------------------------
+----+-------+-------+-------+ +----+--------+-------+-------+              
| id | 名前 | お金 | レベル | | id | 名前 | お金 | レベル |
+----+-------+-------+-------+ +----+--------+-------+-------+
| 1 | トム | 100 | 1 | | 1 | トム | 100 | 1 |
| 2 | ジャック | 200 | 2 | | 2 | ジャック | 200 | 2 |
| 3 | ルーカス | 300 | 3 | | 3 | ルーカス | 300 | 3 |
+----+-------+-------+-------+ +----+--------+-------+-------+
3 行セット (0.00 秒) 3 行セット (0.00 秒)
--------------------------------------------------------------------------------
                        mysql> テスト セット レベル = 100 を更新します (ID = 1)。
                        クエリは正常、1 行が影響を受けました (0.00 秒)
                        一致した行: 1 変更された行: 1 警告: 0
--------------------------------------------------------------------------------
mysql> id=1 のテストから * を選択します。
+----+------+-------+-------+
| ID | 名前 | お金 | レベル |
+----+------+-------+-------+
| 1 | トム | 100 | 100 |
+----+------+-------+-------+
セット内の 1 行 (0.00 秒)
--------------------------------------------------------------------------------
                        mysql> テスト セット レベル = 1000 を更新します (ID = 1)。
                        クエリは正常、1 行が影響を受けました (0.00 秒)
                        一致した行: 1 変更された行: 1 警告: 0
--------------------------------------------------------------------------------
//繰り返し不可能な読み取り//3回読み取り、1回目はレベル1、2回目はレベル100、3回目はレベル1000
mysql> id=1 のテストから * を選択します。
+----+------+-------+-------+
| ID | 名前 | お金 | レベル |
+----+------+-------+-------+
| 1 | トム | 100 | 1000|
+----+------+-------+-------+
セット内の 1 行 (0.00 秒)

2.3 ファントムリード

//2.3 ファントムリーディング セッションA セッションB
mysql> 自動コミットを 0 に設定します。mysql> 自動コミットを 0 に設定します。
クエリは正常、影響を受けた行は 0 行 (0.02 秒) クエリは正常、影響を受けた行は 0 行 (0.02 秒)
セッション トランザクション分離を設定します。セッション トランザクション分離レベルを設定します。コミットされていない読み取りです。
レベル読み取りはコミットされていません。クエリは正常、0 行が影響を受けました (0.00 秒)
クエリは正常、影響を受けた行は 0 行 (0.00 秒)      
mysql> テストから * を選択します。mysql> テストから * を選択します。
--------------------------------------------------------------------------------
+----+-------+-------+-------+ +----+--------+-------+-------+              
| id | 名前 | お金 | レベル | | id | 名前 | お金 | レベル |
+----+-------+-------+-------+ +----+--------+-------+-------+
| 1 | トム | 100 | 1 | | 1 | トム | 100 | 1 |
| 2 | ジャック | 200 | 2 | | 2 | ジャック | 200 | 2 |
| 3 | ルーカス | 300 | 3 | | 3 | ルーカス | 300 | 3 |
+----+-------+-------+-------+ +----+--------+-------+-------+
3 行セット (0.00 秒) 3 行セット (0.00 秒)
--------------------------------------------------------------------------------
                        mysql> テスト セット レベル = 100 を更新します (ID = 1)。
                        クエリは正常、1 行が影響を受けました (0.00 秒)
                        一致した行: 1 変更された行: 1 警告: 0
--------------------------------------------------------------------------------
mysql> id=1 のテストから * を選択します。
+----+------+-------+-------+
| ID | 名前 | お金 | レベル |
+----+------+-------+-------+
| 1 | トム | 100 | 100 |
+----+------+-------+-------+
セット内の 1 行 (0.00 秒)
--------------------------------------------------------------------------------
                        mysql> テストに挿入 (名前、お金、レベル) VALUES ('tim'、250、4);
                        クエリは正常、1 行が影響を受けました (0.01 秒)
--------------------------------------------------------------------------------
//ファントム リード//2 回読み取り、2 回目には Tim のデータが多くなります//rr レベルの場合は、共有モードで現在の読み取り select * from test ロックを使用する必要があります。そうしないと、MVCC のため、Tim のデータを読み取ることができませんmysql> select * from test;
+----+-------+-------+-------+
| ID | 名前 | お金 | レベル |
+----+-------+-------+-------+
| 1 | トム | 100 | 1 |
| 2 | ジャック | 200 | 2 |
| 3 | ルーカス | 300 | 3 |
| 4 | 時間 | 250 | 4 |
+----+-------+-------+-------+
セット内の 4 行 (0.00 秒)

3 ギャップロック(ネットキーロック)

MVCC では、読み取りの場合のファントム読み取りの問題を回避するために、トランザクションは現在 RR レベルで読み取ることができますが、更新を書き込む場合はどうなるでしょうか。範囲を更新しながら範囲に新しいデータを挿入したい場合はどうすればよいでしょうか?

つまり、ギャップ ロックが存在します。特定の間隔でデータを更新すると、この間隔内のすべてのレコードがロックされます。たとえば、ID が 1 から 100 までの XXX を更新すると、ID が 1 から 100 までのすべてのレコードがロックされます。この間隔内にレコードが存在しない場合は、そのレコードもロックされることに注意してください。このとき、別のトランザクションがこの間隔にデータを追加する場合は、前のトランザクションがロック リソースを解放するまで待機する必要があります。

ギャップ ロックを使用する目的は 2 つあります。1 つはファントム リーディングを防ぐこと、もう 1 つは回復と割り当てのニーズを満たすことです。

3.1 レンジギャップロック、明示的な左開区間と右閉区間

//ギャップロック(ネットキーロック)範囲ギャップロック、左オープン右クローズ間隔セッションAセッションB
mysql> 自動コミットを 0 に設定します。mysql> 自動コミットを 0 に設定します。
クエリは正常、影響を受けた行は 0 行 (0.02 秒) クエリは正常、影響を受けた行は 0 行 (0.02 秒)
     
mysql> テストから * を選択します。mysql> テストから * を選択します。
--------------------------------------------------------------------------------
+----+-------+-------+-------+ +----+--------+-------+-------+              
| id | 名前 | お金 | レベル | | id | 名前 | お金 | レベル |
+----+-------+-------+-------+ +----+--------+-------+-------+
| 1 | トム | 100 | 1 | | 1 | トム | 100 | 1 |
| 2 | ジャック | 200 | 2 | | 2 | ジャック | 200 | 2 |
| 3 | ルーカス | 300 | 3 | | 3 | ルーカス | 300 | 3 |
+----+-------+-------+-------+ +----+--------+-------+-------+
3 行セット (0.00 秒) 3 行セット (0.00 秒)
--------------------------------------------------------------------------------
mysql> テストセットレベル=0を更新
金額は0から200までです。
クエリは正常、2 行が影響を受けました (0.02 秒)
一致した行: 2 変更された行: 2 警告: 0
理論的には、範囲は [0,300) に固定されるはずです--------------------------------------------------------------------------------
                        money=0 を挿入waitmysql> テストに挿入 (name, money,level) VALUES ('tim',0,0);
                        エラー 1205 (HY000): ロック待機タイムアウトを超えました。
                        トランザクションを再開してみてください
                        
                        money=90 を挿入waitmysql> テストに挿入 (name, money,level) VALUES ('tim',90,0);
                        エラー 1205 (HY000): ロック待機タイムアウトを超えました。
                        トランザクションを再開してみてください
                        
                        INSERT money=100 WAIT mysql> insert into test (name, money,level) VALUES ('tim',100,0);
                        エラー 1205 (HY000): ロック待機タイムアウトを超えました。
                        トランザクションを再開してみてください
                        
                        INSERT money=299 WAIT mysql> insert into test (name, money,level) VALUES ('tim',299,0);
                        エラー 1205 (HY000): ロック待機タイムアウトを超えました。
                        トランザクションを再開してみてください
                        
                        お金を入れる=300 OK
                        mysql> テストに挿入 (名前、お金、レベル) VALUES ('tim'、300、0);
                        クエリは正常、1 行が影響を受けました (0.00 秒)

3.2 シングルギャップロック暗黙間隔

前のセクションでは、特定の範囲を更新することを指定しましたが、1 つの値だけを更新する場合はどうなるでしょうか。ギャップロックはまだあるのでしょうか?

//ギャップロック(ネットキーロック)シングルギャップロック、左開き右閉じ間隔セッションAセッションB
mysql> 自動コミットを 0 に設定します。mysql> 自動コミットを 0 に設定します。
クエリは正常、影響を受けた行は 0 行 (0.02 秒) クエリは正常、影響を受けた行は 0 行 (0.02 秒)
     
mysql> テストから * を選択します。mysql> テストから * を選択します。
--------------------------------------------------------------------------------
+----+-------+-------+-------+ +----+--------+-------+-------+              
| id | 名前 | お金 | レベル | | id | 名前 | お金 | レベル |
+----+-------+-------+-------+ +----+--------+-------+-------+
| 1 | トム | 100 | 1 | | 1 | トム | 100 | 1 |
| 2 | ジャック | 200 | 2 | | 2 | ジャック | 200 | 2 |
| 3 | ルーカス | 300 | 3 | | 3 | ルーカス | 300 | 3 |
+----+-------+-------+-------+ +----+--------+-------+-------+
3 行セット (0.00 秒) 3 行セット (0.00 秒)
--------------------------------------------------------------------------------
mysql> テストセットレベル=0を更新
ここで、お金 = 200;
クエリは正常、1 行が影響を受けました (0.00 秒)
一致した行: 1 変更された行: 1 警告: 0
理論的には、範囲は [0,300) に固定されるはずです--------------------------------------------------------------------------------
                        お金を入れる=0 OK
                        mysql> テストに挿入 (name, money, level) VALUES ('tim',0,0);
                        クエリは正常、1 行が影響を受けました (0.00 秒)
                        
                        お金を入れる=90 OK
                        mysql> テストに挿入 (名前、お金、レベル) VALUES ('tim'、90、0);
                        クエリは正常、1 行が影響を受けました (0.00 秒)
                        
                        INSERT money=100 WAIT mysql> insert into test (name, money,level) VALUES ('tim',100,0);
                        エラー 1205 (HY000): ロック待機タイムアウトを超えました。
                        トランザクションを再開してみてください
                        
                        INSERT money=150 WAIT mysql> insert into test (name, money,level) VALUES ('tim',150,0);
                        エラー 1205 (HY000): ロック待機タイムアウトを超えました。
                        トランザクションを再開してみてください
                        
                        INSERT money=200 WAITmysql> insert into test (name, money,level) VALUES ('tim',200,0);
                        エラー 1205 (HY000): ロック待機タイムアウトを超えました。
                        トランザクションを再開してみてください
                        
                        INSERT money=240 WAIT mysql> insert into test (name, money,level) VALUES ('tim',240,0);
                        エラー 1205 (HY000): ロック待機タイムアウトを超えました。
                        トランザクションを再開してみてください
                        
                        お金を入れる=300 OK
                        mysql> テストに挿入 (名前、お金、レベル) VALUES ('tim'、300、0);
                        クエリは正常、1 行が影響を受けました (0.00 秒)

間隔が指定されていない場合、暗黙の間隔は、インデックス B+ 番号の前後の 2 つのノードの値によって決定される間隔であり、これも左が開いていて右が閉じています。上記の例では、間隔 [0,300) です。

要約する

これで、MySQL InnoDB ロック メカニズムに関するこの記事は終了です。MySQL InnoDB ロック メカニズムの詳細については、123WORDPRESS.COM の以前の記事を検索するか、次の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • MySQL InnoDB アーキテクチャの概要
  • MySQL InnoDB ReplicaSet の簡単な紹介
  • MySQL InnoDB ストレージエンジンのメモリ管理の詳細な説明
  • MySQL Innodbの主な機能挿入バッファ
  • MySQL InnoDB ロックの概要
  • MySQL の innodb_flush_log_at_trx_commit と sync_binlog を区別する方法
  • MySQLテクノロジーにおけるInnoDBロックの詳細な説明
  • MySQLデータベースエンジンをInnoDBに変更する
  • MySQL InnoDBストレージエンジンについて簡単に説明します
  • MySQL InnoDB テーブルスペース暗号化の例の詳細な説明
  • MySQL InnoDB トランザクション ロック ソースコード分析

<<:  Dockerモードで起動したTomcatのホームページにアクセスすると404エラーが発生する

>>:  Gokudōゲームにおけるフロントエンド知識のまとめ

推薦する

外部キー制約を持つテーブルデータを削除する MySQL メソッドの紹介

MySQLでテーブルやデータを削除する場合、 [エラー] 1451 - 親行を削除または更新できませ...

ページのキャッシュを防ぐソリューション

解決: <head> に次のコードを追加します。コードをコピーコードは次のとおりです。 ...

Node.js+express+socket でオンラインのリアルタイム多人数チャットルームを実現

この記事では、オンラインリアルタイム多人数チャットルームを実現するためのNode.js+expres...

Spark と Scala を使用して Apache アクセス ログを分析する方法

インストールまず、Java と Scala をインストールし、次に Spark をダウンロードしてイ...

MySQL InnoDB のロック機構の詳細な説明

前面に書かれたデータベースは本質的に共有リソースであるため、同時アクセスのパフォーマンスを最大化する...

Mysqlサーバーのインストール、構成、起動、シャットダウン方法の詳細な説明

1. 公式サイトからダウンロード: https://dev.mysql.com/downloads/...

CSS で中空マスク レイヤーを実装するサンプル コード

この記事の内容: ページ中空マスクレイヤー、ページ中空マスクガイドレイヤー、画像中空マスク通常のマス...

MySQL の条件文で 1 つの情報しか読み取れない問題に対する 2 つの解決策

今日、私の同僚が MYSQL クエリ ステートメントの作成時に非常に奇妙な問題に遭遇しました。MyS...

Vue3 での Teleport の使用に関する詳細な説明

目次テレポートの目的テレポートの仕組みこの記事では、以下の内容を取り上げます。テレポートの目的テレポ...

HTML マウス CSS コントロール

一般的に、マウスは上向きの斜め矢印として表示され、テキストの上に移動すると垂直線になり、ハイパーリン...

JS配列の次元削減のいくつかの方法の詳細な説明

2次元配列の次元削減配列インスタンスメソッド concat と ES6 スプレッド演算子を使用した次...

Linux で圧縮ファイルの内容を表示する 10 の方法 (要約)

一般的に、アーカイブされたファイルや圧縮されたファイルの内容を表示するには、まず解凍してから表示する...

フロントエンドの vue+express ファイルのアップロードとダウンロードの例

新しいserver.jsを作成する糸初期化 -y 糸を追加エクスプレスノードモン -D var ex...

Windows/Mac で Docker を使用して MySQL (utf8 を含む) をインストールする

目次1. MacへのDockerのインストール2. Win 10 システムでの Docker のイン...

FirefoxでCookieとお気に入りをインポートおよびエクスポートする方法

Firefox は、多くの拡張機能とプラグインを備えた、よく使用されるブラウザです。IE に比べて多...