InnoDB
では,2のロックタ(共有 (年代
)ロックと排他 (X
)ロックがある標準の行レベルロックが実装されます。レコド,ギャップ,およびネクストキ,セクション14.2.6 " InnoDBのレコド,ギャップ,およびネクストキロック"を参照してください。
共有 (
年代
)ロックでは,ロックを保持するトランザクションによる行の読み取りが許可されます。排他 (
X
)ロックでは,ロックを保持するトランザクションによる行の更新または削除が許可されます。
トランザクションT1
が行r
に対する共有(年代
)ロックを保持している場合,別のトランザクションT2
からの行r
に対するロック要求は次のように処理されます。
T2
による年代
ロックに対するリクエストは,すぐに付与できます。結果として,T1
とT2
の両方がr
上で年代
ロックを保持します。T2
によるX
ロックに対するリクエストは,すぐに付与できません。
トランザクションT1
が行r
上で排他(X
)ロックを保持している場合は,r
上のいずれかのタ邮箱プのロックに対する一部の個別のトランザクションT2
からのリクエストは,すぐに付与できません。代わりに,トランザクションT2
は,行r
上でトランザクションT1
のロックが解放されるまで待機する必要があります。
ンテンションロック
さらに,InnoDB
では,レコドロックとテブル全体のロックが共存することを許可する複数粒度ロックもサポトされています。複数粒度レベルでのロックを実用的にするために,ンテンションロックと呼ばれる追加のロックタ邮箱プが使用されます。ンテンションロックとは、あとでトランザクションがそのテーブル内の行で必要となるロックのタイプ (共有または排他) を示すInnoDB
のテブルロックです。トランザクションT
がテブルt
上に指定されたタプのロックをリクエストしたと仮定すると,InnoDB
で使用されるereplicationンテンションロックには,次の2 ereplicationタereplicationプがあります。
たとえば,选择……共享模式锁定
は是
ロックを設定し,选择……更新
は9
ロックを設定します。
ンテンションロックの手順は次のとおりです。
トランザクションがテブル
t
のある行の年代
ロックを取得するには,まずt
の是
またはそれより強いロックを取得する必要があります。トランザクションがある行の
X
ロックを取得するには,まずt
の9
ロックを取得する必要があります。
これらのルルをまとめる際は,次に示すロックタ邮箱プ互換性マトリクスを使用すると便利です。
X |
9 |
年代 |
是 |
|
---|---|---|---|---|
X |
競合 | 競合 | 競合 | 競合 |
9 |
競合 | 互換 | 競合 | 互換 |
年代 |
競合 | 競合 | 互換 | 互換 |
是 |
競合 | 互換 | 互換 | 互換 |
ロックに既存のロックとの互換性がある場合は,リクエスト元のトランザクションにロックが付与されますが,既存のロックと競合している場合は,ロックが付与されません。トランザクションは,競合している既存のロックが解放されるまで待機します。ロックリクエストが既存のロックと競合し,デッドロックが発生するために付与できない場合は,エラが発生します。
したがって,ンテンションロックでは,完全なテ,ブルリクエスト(锁表……写
など)以外は何もブロックされません。9
および是
ロックの主な目的は,だれかが行をロックしていることや,テーブル内の行をロックしようとしていることを示すことです。
デッドロックの例
次の例は,ロックリクエストによってデッドロックが発生したときに,どのようにエラーが発生するのかを示しています。aとbの2。
最初に,クラ1。トランザクション内で,一个は共有モドで選択した行で年代
ロックを取得します。
CREATE TABLE t (i INT) = InnoDB;查询OK, 0行影响(1.07秒)mysql> INSERT INTO t (i) VALUES(1);查询OK, 1 row affected (0.09 sec) mysql> START TRANSACTION;查询OK, 0 rows affected (0.00 sec) mysql> SELECT * FROM WHERE i = 1 LOCK IN SHARE MODE;+------+ | 我 | +------+ | 1 | +------+ 1行集(0.10秒)
次に,クラe eアントbがトランザクションを開始し,テe eブルから行を削除しようとします。
mysql >开始交易;查询OK, 0 rows affected (0.00 sec) mysql> DELETE FROM t WHERE i = 1;
削除操作を行うには,X
ロックが必要です。クラアントaが保持している年代
ロックとの互換性がないために,ロックを付与できません。そのため,リクエストはその行のロックリクエストのキューに入れられ,クライアントBはブロックされます。
最後に,クラe .アントaもテe .ブルから行を削除しようとします。
删除t WHERE i = 1;错误1213(40001):当试图获得锁时发现死锁;试着重新启动事务
クラアントaは行を削除するためにX
ロックが必要であるため,ここでデッドロックが発生します。ただし,クラeアントbはすでにX
ロックに対するリクエストを持っていて,クラeアントaがその年代
ロックを解放するまで待機しているため,そのロックリクエストを付与することはできません。BによるX
ロックに対する以前のリクエストが原因で,一个が保持している年代
ロックをX
ロックにアップグレドすることもできません。その結果,InnoDB
はクラアントのいずれかに対してエラを生成し,そのロックを解放します。クラアントは,次のエラを返します。
错误1213(40001):当试图获得锁时发现死锁;试着重新启动事务
この時点で,ほかのクライアントに対するロックリクエストを付与できるようになり,テーブルから行が削除されます。
InnoDB Monitorの出力の最新检测到死锁
セクションには,「在锁表等待图中搜索过深或过长,将回滚后续事务」というメッセジが含まれます。これは,待機リスト上のトランザクション数が200の制限に達したことを示します。この制限は,LOCK_MAX_DEPTH_IN_DEADLOCK_CHECK
で定義されます。200年個のトランザクションを超える待機リストはデッドロックとして処理され,待機リストをチェックしようとするトランザクションはロールバックされます。
ロックスレッドが待機リスト上のトランザクションが所有する1000000個を超えるロックを参照する必要がある場合も,同じエラーが発生する可能性があります。1,000,000個のロック制限は,LOCK_MAX_N_STEPS_IN_DEADLOCK_CHECK
で定義されます。