記事ディレクトリ
ギャップロック
前書き
ギャップロックは、特定の範囲のデータベーステーブルに対するロックであり、行ロックを使用して次のキーロックを形成し、反復可能な読み取りトランザクション分離レベルで生成されるファントム読み取りの問題を解決できます。ファントム読み取りとは、トランザクションが範囲クエリを実行するときであり、クエリの前後の結果は異なります。
原則として
MySQLが繰り返し可能な読み取りトランザクション分離レベルでロックするルールを記録するには:
- ロックの基本単位はネクストキーロックです。これは、開閉する前に開くという原則です。
- クエリプロセス中にアクセスされるオブジェクトは、ロックを増加させます
- インデックスに対する同等のクエリ-一意のインデックスがロックされると、次のキーのロックが行ロックにアップグレードされます
- インデックスの同等のクエリ-右に移動するときに、最後の値がクエリの要件を満たしていない場合、次のキーのロックはギャップロックになります
- 一意のインデックスは、範囲クエリ中に条件を満たさない最初の値にアクセスします
上記の原則を事例を通じて説明する
先声明一下,下面的这些案例都是基于可重复读事务隔离级别的
データ紹介
ここで、いくつかのデータがあるとします。
ステップ | id(一意のインデックス) | c(通常のインデックス) | d(インデックスなし) |
---|---|---|---|
1 | 1 | 1 | 1 |
2 | 5 | 5 | 5 |
3 | 10 | 10 | 10 |
4 | 15 | 15 | 15 |
ファントム読み取りの問題を解決するために、上記のデータは、上記のデータの各行に対してロックされるだけでなく、更新時に中間値の範囲に対してもロックされます。このロックは、ギャップロックと呼ばれます。このように、行ロック+ギャップロックは次のキーロックを構成し、このロックの情報は次のとおりです。(-°、1]、(1,5]、(5,10)、(10,15]、(15、+ supernum) ]、(その中で、supernumは、次のキーのロックが左右の開閉の原則であることを保証するためにMySQLデータベースによって維持される最大値です)
場合
ケース1:ギャップロックの単純なケース
ステップ | トランザクションA | トランザクションB |
---|---|---|
1 | ベギン; 更新のためにid = 3であるテーブルから*を選択します |
|
2 | - | tabble value(4,4,4)ブロックに挿入し ます。 |
3 | コミット; | - |
これは単純なケースです。彼のプロセスを分析してみましょう。
- 上記の2つのトランザクションがある場合、トランザクションAの操作により、データベースに(1,5]範囲ロックが追加されます。このとき、トランザクションBはデータを挿入できず、ブロック状態になっています。
ケース2:ギャップロックデッドロックの問題
ステップ | トランザクションA | トランザクションB |
---|---|---|
1 | ベギン; 更新のためにid = 3であるテーブルから*を選択します |
|
2 | - | ベギン; 更新のためにid = 4であるテーブルから*を選択します |
3 | - | テーブルvalue(2,2,2)ブロックに挿入します 。 |
3 | テーブルvalue(2,2,2) ブロックに挿入します。 |
- |
相互に排他的な書き込みロックとは異なり、ギャップロックは相互に排他的ではありません。両方のトランザクションがこのギャップロックを取得できますが、このギャップロックを取得した後、他のトランザクションはこのギャップロックに対してDDL操作を実行できなくなります。デッドロック
ケース3:同等のクエリ-一意のインデックス
ステップ | トランザクションA | トランザクションB | トランザクションC |
---|---|---|---|
1 | 開始; テーブルセットの更新d = d + 1ここで、id = 7 |
- | - |
2 | - | テーブルvalue(8,8,8)ブロックに挿入します 。 |
- |
3 | - | - | テーブルセットd = d + 1を更新します。ここで、id = 10 |
1. MySQLがデータベースに対して生成するロックの範囲を見てみましょう。(5,10)
2。上記の原則4によれば、この範囲10の最後の値がチェックしたいid = 7と等しくないことがわかります。このネクストキーロックはギャップロック(5、10)に縮退します
。3。したがって、トランザクションCの操作はブロックされていないが、トランザクションBによって実行された挿入操作はブロックされていると説明できます。
ケース4:同等のクエリ-通常のインデックス
ステップ | トランザクションA | トランザクションB | トランザクションC |
---|---|---|---|
1 | 開始; 共有モードでc = 5ロックするテーブルからIDを選択します |
- | - |
2 | - | テーブルセットd = d + 1を更新します。ここで、id = 5 | - |
3 | - | - | テーブルvalues(7,7,7)ブロックに挿入します 。 |
1、先来看看MySQL会给数据库生成什么范围的锁:(0,5],(5,10]
2、由于查询是等值查询,并且最后一个值不满足查询要求,故退化为间隙锁(5,10)
3、事务B能正常执行不阻塞的原因就是,事务A走的是覆盖索引并没有对主键索引加锁,所以B能正常执行
4、事务C插入的信息是7,在(5,10)之间,故会阻塞。