本文主要介绍InnoDB
存储引擎的Next-Key Lock
MVCC
InnoDB支持MVCC
,与之MVCC
相对的是LBCC
MVCC中读操作
分两类:Snapshot Read
(不加锁
)和Current Read
(加锁
)
MVCC的好处:**Snapshot Read不加锁
**,并发性能好
,适用于常规的JavaWeb
项目(OLTP
应用)
隔离级别 InnoDB支持4种事务隔离级别(Isolation Level
)
隔离级别
描述
READ UNCOMMITTED (RUC)
可以读取到其他事务中尚未提交
的内容,生产环境中不会使用
READ COMMITTED (RC)
可以读取到其他事务中已经提交
的内容,Current Read会加锁
,存在幻读现象
,Oracle
和SQL Server
的默认事务隔离级别为RC
REPEATABLE READ (RR)
保证事务的隔离性
,Current Read会加锁
,同时会加Gap Lock
,不存在幻读现象
,InnoDB
的默认事务隔离级别为RR
SERIALIZABLE
MVCC退化为LBCC
,不区分Snapshot Read
和Current Read
,读
操作加S Lock
,写
操作加X Lock
,读写冲突,并发性能差
行锁
InnoDB实现了两种标准的行锁
(Row-Level Lock
):共享锁(Shared(S) Lock
)、排它锁(Exclusive(X) Lock
)
S Lock
:允许事务持有该锁去*读取一行数据
*
X Lock
:允许事务持有该锁去*更新或删除一行数据
*
S Lock
与X Lock
的兼容性
锁的算法 Record Lock
Record Lock
即行锁,用于锁住Index Record
(索引记录),分为S Lock
和X Lock
如果表中没有显式定义的主键
或非NULL唯一的索引
,InnoDB将自动创建6 Bytes的ROWID
的隐藏主键
Gap Lock
用于锁住Index Record
之间的间隙
如果是通过唯一索引来搜索一行记录
的时候,不需要使用Gap Lock
,此时Next-Key
降级为Record Lock
Gap S-Lock
与Gap X-Lock
是兼容的
Gap Lock
只能_**阻止其他事务在该Gap中插入记录
_,但 无法阻止
**其他事务获取同一个Gap
上的Gap Lock
禁用Gap Lock
的两种方式
将事务隔离级别设置为READ COMMITTED
将变量innodb_locks_unsafe_for_binlog
(已弃用)设置为1
Next-Key Lock
Next-Key Lock
= Record Lock
+ Gap Lock
若索引a为10、11、13、20,可锁定的区间为(-∞, 10]
、(10, 11]
、(11, 13]
、(13, 20]
、(20, +∞)
若执行Select...Where a=13 For Update
,将在a=13
上有1个X Lock
和在(11, 13)
有1个Gap Lock
a=13
的下一个键为a=20
,将在a=20
有1个X Lock
,在(13, 20)
有1个Gap Lock
因此,在a=13
上有1个X Lock
,在(11, 20]
上的有1个Gap Lock
也可以分解为在a=13
和a=20
上有2个X Lock
,在(11,13)
和(13,20)
上有2个Gap Lock
在InnoDB默认事务隔离级别REPEATABLE READ(RR)
下,支持Next-Key Lock
11个实例
下面11个实例仅仅考虑RC
与RR
的事务隔离级别
RR
支持Next-Key Lock
、Gap Lock
和Record Lock
,RC
仅支持Record Lock
RC/RR+Clustered Index+Equal Match
事务隔离级别READ COMMITTED(RC)
或REPEATABLE READ(RR)
存在显式定义
主键
WHERE
等值匹配成功
注:RR
支持Next-Key Lock
,在通过唯一索引来搜索一行记录
时,Next-Key Lock
降级为Record Lock
,此时与RC
一致,下面实例仅以RC
进行说明
表初始化 1 2 3 4 5 6 mysql> CREATE TABLE t ( a INT NOT NULL PRIMARY KEY ) ENGINE= INNODB CHARSET= LATIN1 ROW_FORMAT= COMPACT; Query OK, 0 rows affected (0.02 sec) mysql> INSERT INTO t VALUES (10 ),(20 ),(30 ),(40 ),(50 ),(60 ),(70 ),(80 ); Query OK, 8 rows affected (0.01 sec) Records: 8 Duplicates: 0 Warnings: 0
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 mysql> SET SESSION TX_ISOLATION= 'READ-COMMITTED' ; Query OK, 0 rows affected (0.00 sec) mysql> BEGIN ; Query OK, 0 rows affected (0.00 sec) mysql> SELECT * FROM t WHERE a= 30 FOR UPDATE ; + | a | + | 30 | + 1 row in set (0.01 sec)mysql> SELECT trx_id,trx_state,trx_requested_lock_id,trx_isolation_level FROM INFORMATION_SCHEMA.INNODB_TRX; + | trx_id | trx_state | trx_requested_lock_id | trx_isolation_level | + | 1322763 | RUNNING | NULL | READ COMMITTED | + 1 row in set (0.00 sec)
将Session A
的事务隔离级别设置为READ COMMITTED
事务1322763
通过SELECT...FOR UPDATE
操作获得了聚集索引a
(Clustered Index
)上30
的X Lock
Session B 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 mysql> SET SESSION TX_ISOLATION= 'READ-COMMITTED' ; Query OK, 0 rows affected (0.00 sec) mysql> BEGIN ; Query OK, 0 rows affected (0.00 sec) mysql> INSERT INTO t SELECT 25 ; Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> INSERT INTO t SELECT 35 ; Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> SELECT trx_id,trx_state,trx_requested_lock_id,trx_isolation_level FROM INFORMATION_SCHEMA.INNODB_TRX; + | trx_id | trx_state | trx_requested_lock_id | trx_isolation_level | + | 1322764 | RUNNING | NULL | READ COMMITTED | | 1322763 | RUNNING | NULL | READ COMMITTED | + 2 rows in set (0.01 sec)mysql> SELECT * FROM t WHERE a= 30 LOCK IN SHARE MODE; # Blocked
将Session B
的事务隔离级别设置为READ COMMITTED
成功插入a=25
和a=35
,说明在(20,30)
和(30,40)
上没有Gap Lock
事务1322764
尝试通过SELECT...LOCK IN SHARE MODE
获得a=30
的S Lock
,由于S lock
与X Lock
不兼容,且此时事务1322763
持有对应的X Lock
,所以事务1322764
被阻塞
(详细信息见下节)
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS; + | lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data | + | 1322764 :389 :3 :4 | 1322764 | S | RECORD | `test`.`t` | PRIMARY | 389 | 3 | 4 | 30 | | 1322763 :389 :3 :4 | 1322763 | X | RECORD | `test`.`t` | PRIMARY | 389 | 3 | 4 | 30 | + 2 rows in set , 1 warning (0.02 sec)mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS; + | requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id | + | 1322764 | 1322764 :389 :3 :4 | 1322763 | 1322763 :389 :3 :4 | + 1 row in set , 1 warning (1.18 sec)mysql> SELECT trx_id,trx_state,trx_requested_lock_id,trx_isolation_level FROM INFORMATION_SCHEMA.INNODB_TRX; + | trx_id | trx_state | trx_requested_lock_id | trx_isolation_level | + | 1322764 | LOCK WAIT | 1322764 :389 :3 :4 | READ COMMITTED | | 1322763 | RUNNING | NULL | READ COMMITTED | + 2 rows in set (0.00 sec)mysql> SHOW ENGINE INNODB STATUS\G LIST OF TRANSACTIONS FOR EACH SESSION: mysql tables in use 1 , locked 1 LOCK WAIT 2 lock struct(s), heap size 1136 , 1 row lock(s), undo log entries 2 MySQL thread id 139 , OS thread handle 140648641087232 , query id 2146 localhost root statistics SELECT * FROM t WHERE a= 30 LOCK IN SHARE MODERECORD LOCKS space id 389 page no 3 n bits 80 index PRIMARY of table `test`.`t` trx id 1322764 lock mode S locks rec but not gap waiting Record lock, heap no 4 PHYSICAL RECORD: n_fields 3 ; compact format; info bits 0 0 : len 4 ; hex 8000001 e; asc ;; 1 : len 6 ; hex 000000142 f02; asc / ;; 2 : len 7 ; hex dc000001af012a; asc * ;; 2 lock struct(s), heap size 1136 , 1 row lock(s)MySQL thread id 138 , OS thread handle 140648641488640 , query id 2150 localhost root starting
lock_index
为PRIMARY
,说明锁住的是聚集索引a
(Clustered Index
)
trx id 1322764 lock mode S locks rec but not gap
表示事务1322764
想要获得S Lock
,不需要Gap Lock
示意图
RC+Clustered Index+Equal Not Match
事务隔离级别READ COMMITTED(RC)
存在显式定义
主键
WHERE
等值匹配不成功
表初始化 1 2 3 4 5 6 mysql> CREATE TABLE t ( a INT NOT NULL PRIMARY KEY ) ENGINE= INNODB CHARSET= LATIN1 ROW_FORMAT= COMPACT; Query OK, 0 rows affected (0.02 sec) mysql> INSERT INTO t VALUES (10 ),(20 ),(30 ),(40 ),(50 ),(60 ),(70 ),(80 ); Query OK, 8 rows affected (0.01 sec) Records: 8 Duplicates: 0 Warnings: 0
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 mysql> SET SESSION TX_ISOLATION= 'READ-COMMITTED' ; Query OK, 0 rows affected (0.00 sec) mysql> BEGIN ; Query OK, 0 rows affected (0.00 sec) mysql> SELECT * FROM t WHERE a= 35 FOR UPDATE ; Empty set (0.00 sec)mysql> SELECT trx_id,trx_state,trx_requested_lock_id,trx_isolation_level FROM INFORMATION_SCHEMA.INNODB_TRX; + | trx_id | trx_state | trx_requested_lock_id | trx_isolation_level | + | 1322801 | RUNNING | NULL | READ COMMITTED | + 1 row in set (0.01 sec)
将Session A
的事务隔离级别设置为READ COMMITTED
事务1322801
尝试通过SELECT...FOR UPDATE
操作获得了聚集索引a
(Clustered Index
)上35
的X Lock
,但a=35
不存在,并不加任何锁
Session B 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 mysql> SET SESSION TX_ISOLATION= 'READ-COMMITTED' ; Query OK, 0 rows affected (0.00 sec) mysql> BEGIN ; Query OK, 0 rows affected (0.00 sec) mysql> INSERT INTO t SELECT 34 ; Query OK, 1 row affected (0.01 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> INSERT INTO t SELECT 36 ; Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> INSERT INTO t SELECT 35 ; Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> SELECT trx_id,trx_state,trx_requested_lock_id,trx_isolation_level FROM INFORMATION_SCHEMA.INNODB_TRX; + | trx_id | trx_state | trx_requested_lock_id | trx_isolation_level | + | 1322802 | RUNNING | NULL | READ COMMITTED | | 1322801 | RUNNING | NULL | READ COMMITTED | + 2 rows in set (0.00 sec)
将Session B
的事务隔离级别设置为READ COMMITTED
成功插入a=34
和a=36
,说明在(30,40)
上没有Gap Lock
成功插入a=35
,说明在a=35
上没有X Lock
RR+Clustered Index+Equal Not Match
事务隔离级别REPEATABLE READ(RR)
存在显式定义
主键
WHERE
等值匹配不成功
表初始化 1 2 3 4 5 6 mysql> CREATE TABLE t ( a INT NOT NULL PRIMARY KEY ) ENGINE= INNODB CHARSET= LATIN1 ROW_FORMAT= COMPACT; Query OK, 0 rows affected (0.02 sec) mysql> INSERT INTO t VALUES (10 ),(20 ),(30 ),(40 ),(50 ),(60 ),(70 ),(80 ); Query OK, 8 rows affected (0.01 sec) Records: 8 Duplicates: 0 Warnings: 0
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 mysql> SET SESSION TX_ISOLATION= 'REPEATABLE-READ' ; Query OK, 0 rows affected (0.00 sec) mysql> BEGIN ; Query OK, 0 rows affected (0.00 sec) mysql> SELECT * FROM t WHERE a= 35 FOR UPDATE ; Empty set (0.00 sec)mysql> SELECT trx_id,trx_state,trx_requested_lock_id,trx_isolation_level FROM INFORMATION_SCHEMA.INNODB_TRX; + | trx_id | trx_state | trx_requested_lock_id | trx_isolation_level | + | 1323280 | RUNNING | NULL | REPEATABLE READ | + 1 row in set (0.00 sec)
将Session A
的事务隔离级别设置为REPEATABLE-READ
事务1323280
尝试通过SELECT...FOR UPDATE
操作获得了聚集索引a
(Clustered Index
)上35
的X Lock
,但a=35
不存在,在(30,40)
上加上Gap Lock
Session B 1 2 3 4 5 6 7 mysql> SET SESSION TX_ISOLATION= 'REPEATABLE-READ' ; Query OK, 0 rows affected (0.00 sec) mysql> BEGIN ; Query OK, 0 rows affected (0.00 sec) mysql> INSERT INTO t SELECT 35 ; # Blocked
将Session B
的事务隔离级别设置为REPEATABLE-READ
Session B
的事务尝试插入a=35
,但由于事务1323280
已经持有了(30,40)
上的Gap Lock
,因此被阻塞(详细信息见下节)
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS; + | lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data | + | 1323281 :391 :3 :5 | 1323281 | X,GAP | RECORD | `test`.`t` | PRIMARY | 391 | 3 | 5 | 40 | | 1323280 :391 :3 :5 | 1323280 | X,GAP | RECORD | `test`.`t` | PRIMARY | 391 | 3 | 5 | 40 | + 2 rows in set , 1 warning (0.00 sec)mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS; + | requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id | + | 1323281 | 1323281 :391 :3 :5 | 1323280 | 1323280 :391 :3 :5 | + 1 row in set , 1 warning (0.00 sec)mysql> SELECT trx_id,trx_state,trx_requested_lock_id,trx_isolation_level FROM INFORMATION_SCHEMA.INNODB_TRX; + | trx_id | trx_state | trx_requested_lock_id | trx_isolation_level | + | 1323281 | LOCK WAIT | 1323281 :391 :3 :5 | REPEATABLE READ | | 1323280 | RUNNING | NULL | REPEATABLE READ | + 2 rows in set (0.00 sec)mysql> SHOW ENGINE INNODB STATUS\G LIST OF TRANSACTIONS FOR EACH SESSION: mysql tables in use 1 , locked 1 LOCK WAIT 2 lock struct(s), heap size 1136 , 1 row lock(s) MySQL thread id 5 , OS thread handle 140546164094720 , query id 119 localhost root executing INSERT INTO t SELECT 35 RECORD LOCKS space id 391 page no 3 n bits 80 index PRIMARY of table `test`.`t` trx id 1323281 lock_mode X locks gap before rec insert intention waiting Record lock, heap no 5 PHYSICAL RECORD: n_fields 3 ; compact format; info bits 0 0 : len 4 ; hex 80000028 ; asc (;; 1 : len 6 ; hex 000000142 f41; asc / A;; 2 : len 7 ; hex a7000001fd0137; asc 7 ;; 2 lock struct(s), heap size 1136 , 1 row lock(s)MySQL thread id 4 , OS thread handle 140546164295424 , query id 123 localhost root starting mysql> INSERT INTO t SELECT 35 ; Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0
在事务隔离级别为REPEATABLE READ
时,尝试给不存在
的值上锁,会产生Gap Lock
在事务1323280
插入a=35
成功,因为其他事务(1323281
)暂不持有包含a=35
的Gap Lock
,因此无法阻塞事务1323280
的插入操作
插入成功后,事务1323280
持有a=35
的X Lock
Session B 1 2 3 4 5 mysql> INSERT INTO t SELECT 35 ; # Timeout ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction mysql> SELECT * FROM t WHERE a= 37 FOR UPDATE ; Empty set (0.00 sec)
事务1323280
持有(30,40)
的Gap Lock
,但无法阻止事务1323281
获得(35,40)
上的Gap Lock
(事务1323280
已获得a=35
的X Lock
)
Session A 1 2 3 4 5 mysql> INSERT INTO t SELECT 33 ; Query OK, 1 row affected (0.01 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> INSERT INTO t SELECT 36 ; # Blocked
事务1323280
持有(30,40)
上的Gap Lock
,另一个事务1323281
持有(35,40)
上的Gap Lock
插入a=33
不被阻塞,插入成功后事务1323280
持有a=33
的X Lock
插入a=36
被事务1323281
持有(35,40)
上的Gap Lock
阻塞(详细信息见下节)
Session B 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS; + | lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data | + | 1323280 :391 :3 :5 | 1323280 | X,GAP | RECORD | `test`.`t` | PRIMARY | 391 | 3 | 5 | 40 | | 1323281 :391 :3 :5 | 1323281 | X,GAP | RECORD | `test`.`t` | PRIMARY | 391 | 3 | 5 | 40 | + 2 rows in set , 1 warning (0.00 sec)mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS; + | requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id | + | 1323280 | 1323280 :391 :3 :5 | 1323281 | 1323281 :391 :3 :5 | + 1 row in set , 1 warning (0.00 sec)mysql> SELECT trx_id,trx_state,trx_requested_lock_id,trx_isolation_level FROM INFORMATION_SCHEMA.INNODB_TRX; + | trx_id | trx_state | trx_requested_lock_id | trx_isolation_level | + | 1323281 | RUNNING | NULL | REPEATABLE READ | | 1323280 | LOCK WAIT | 1323280 :391 :3 :5 | REPEATABLE READ | + 2 rows in set (0.00 sec)mysql> SHOW ENGINE INNODB STATUS\G; LIST OF TRANSACTIONS FOR EACH SESSION: 2 lock struct(s), heap size 1136 , 2 row lock(s)MySQL thread id 5 , OS thread handle 140546164094720 , query id 131 localhost root starting SHOW ENGINE INNODB STATUSmysql tables in use 1 , locked 1 LOCK WAIT 3 lock struct(s), heap size 1136 , 4 row lock(s), undo log entries 2 MySQL thread id 4 , OS thread handle 140546164295424 , query id 127 localhost root executing INSERT INTO t SELECT 36 RECORD LOCKS space id 391 page no 3 n bits 80 index PRIMARY of table `test`.`t` trx id 1323280 lock_mode X locks gap before rec insert intention waiting Record lock, heap no 5 PHYSICAL RECORD: n_fields 3 ; compact format; info bits 0 0 : len 4 ; hex 80000028 ; asc (;; 1 : len 6 ; hex 000000142 f41; asc / A;; 2 : len 7 ; hex a7000001fd0137; asc 7 ;;
RC+Clustered Index+Range
事务隔离级别READ COMMITTED(RC)
存在显式定义
主键
WHERE采用RANGE
匹配
表初始化 1 2 3 4 5 6 mysql> CREATE TABLE t ( a INT NOT NULL PRIMARY KEY ) ENGINE= INNODB CHARSET= LATIN1 ROW_FORMAT= COMPACT; Query OK, 0 rows affected (0.01 sec) mysql> INSERT INTO t VALUES (10 ),(20 ),(30 ),(40 ),(50 ); Query OK, 5 rows affected (0.01 sec) Records: 5 Duplicates: 0 Warnings: 0
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 mysql> SET SESSION TX_ISOLATION= 'READ-COMMITTED' ; Query OK, 0 rows affected (0.00 sec) mysql> BEGIN ; Query OK, 0 rows affected (0.00 sec) mysql> SELECT * FROM t WHERE a> 15 AND a< 45 FOR UPDATE ; + | a | + | 20 | | 30 | | 40 | + 3 rows in set (0.00 sec)mysql> SELECT trx_id,trx_state,trx_requested_lock_id,trx_isolation_level FROM INFORMATION_SCHEMA.INNODB_TRX; + | trx_id | trx_state | trx_requested_lock_id | trx_isolation_level | + | 1323886 | RUNNING | NULL | READ COMMITTED | + 1 row in set (0.00 sec)
将Session A
的事务隔离级别设置为READ COMMITTED
事务1323886
将获得聚集索引a
上20
、30
、40
上的X Lock
Session B 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 mysql> SET SESSION TX_ISOLATION= 'READ-COMMITTED' ; Query OK, 0 rows affected (0.00 sec) mysql> BEGIN ; Query OK, 0 rows affected (0.00 sec) mysql> INSERT INTO t SELECT 25 ; Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> INSERT INTO t SELECT 35 ; Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> SELECT * FROM t WHERE a= 30 FOR UPDATE ; # Blocked
将Session B
的事务隔离级别设置为READ COMMITTED
事务1323887
成功插入a=25
和a=35
,表明(20,30)
和(30,40)
上不存在Gap Lock
因为事务1323886
已经持有a=30
的X Lock
,因此事务1323887
被阻塞(详细信息见下节)
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS; + | lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data | + | 1323887 :399 :3 :4 | 1323887 | X | RECORD | `test`.`t` | PRIMARY | 399 | 3 | 4 | 30 | | 1323886 :399 :3 :4 | 1323886 | X | RECORD | `test`.`t` | PRIMARY | 399 | 3 | 4 | 30 | + 2 rows in set , 1 warning (0.00 sec)mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS; + | requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id | + | 1323887 | 1323887 :399 :3 :4 | 1323886 | 1323886 :399 :3 :4 | + 1 row in set , 1 warning (0.01 sec)
示意图
RR+Clustered Index+Range
事务隔离级别REPEATABLE READ(RR)
存在显式定义
主键
WHERE采用RANGE
匹配
表初始化 1 2 3 4 5 6 mysql> CREATE TABLE t ( a INT NOT NULL PRIMARY KEY ) ENGINE= INNODB CHARSET= LATIN1 ROW_FORMAT= COMPACT; Query OK, 0 rows affected (0.01 sec) mysql> INSERT INTO t VALUES (10 ),(20 ),(30 ),(40 ),(50 ); Query OK, 5 rows affected (0.01 sec) Records: 5 Duplicates: 0 Warnings: 0
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 mysql> SET SESSION TX_ISOLATION= 'REPEATABLE-READ' ; Query OK, 0 rows affected (0.00 sec) mysql> BEGIN ; Query OK, 0 rows affected (0.00 sec) mysql> SELECT * FROM t WHERE a> 15 AND a< 25 FOR UPDATE ; + | a | + | 20 | + 2 rows in set (0.00 sec)mysql> SELECT trx_id,trx_state,trx_requested_lock_id,trx_isolation_level FROM INFORMATION_SCHEMA.INNODB_TRX; + | trx_id | trx_state | trx_requested_lock_id | trx_isolation_level | + | 1332194 | RUNNING | NULL | REPEATABLE READ | + 1 row in set (0.00 sec)
将Session A
的事务隔离级别设置为REPEATABLE READ
事务1332194
将获得聚集索引a
上20
的X Lock
,并将对应地获得(10,20)
上的Gap Lock
依据Next-Key Lock
,事务1332194
还将获得聚集索引a
上30
的X Lock
以及(20,30)
上的Gap Lock
Session B 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 mysql> SET SESSION TX_ISOLATION= 'REPEATABLE-READ' ; Query OK, 0 rows affected (0.00 sec) mysql> BEGIN ; Query OK, 0 rows affected (0.00 sec) mysql> INSERT INTO t SELECT 5 ; Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> INSERT INTO t SELECT 35 ; Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> INSERT INTO t SELECT 45 ; Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> INSERT INTO t SELECT 55 ; Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> INSERT INTO t SELECT 29 ; # Blocked
将Session B
的事务隔离级别设置为REPEATABLE READ
成功插入5
、35
、45
、55
,表明事务1332194
并没有持有(-∞,10)
、(30,40)
、(40,50)
和(50,+∞)
上的Gap Lock
事务1332194
已持有(20,30)
上的Gap Lock
,因此事务1332194
插入29
会被阻塞(详细信息见下节)
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS; + | lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data | + | 1332195 :486 :3 :4 | 1332195 | X,GAP | RECORD | `test`.`t` | PRIMARY | 486 | 3 | 4 | 30 | | 1332194 :486 :3 :4 | 1332194 | X | RECORD | `test`.`t` | PRIMARY | 486 | 3 | 4 | 30 | + 2 rows in set , 1 warning (0.00 sec)mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS; + | requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id | + | 1332195 | 1332195 :486 :3 :4 | 1332194 | 1332194 :486 :3 :4 | + 1 row in set , 1 warning (0.00 sec)mysql> SELECT trx_id,trx_state,trx_requested_lock_id,trx_isolation_level FROM INFORMATION_SCHEMA.INNODB_TRX; + | trx_id | trx_state | trx_requested_lock_id | trx_isolation_level | + | 1332195 | LOCK WAIT | 1332195 :486 :3 :4 | REPEATABLE READ | | 1332194 | RUNNING | NULL | REPEATABLE READ | + 2 rows in set (0.00 sec)
Session B 1 2 3 4 mysql> INSERT INTO t SELECT 29 ; # Timeout ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction mysql> INSERT INTO t SELECT 11 ; # Blocked
事务1332195
插入11
会被阻塞,原因同插入29
一致,不再赘述,详细信息见下节
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS; + | lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data | + | 1332195 :486 :3 :3 | 1332195 | X,GAP | RECORD | `test`.`t` | PRIMARY | 486 | 3 | 3 | 20 | | 1332194 :486 :3 :3 | 1332194 | X | RECORD | `test`.`t` | PRIMARY | 486 | 3 | 3 | 20 | + 2 rows in set , 1 warning (0.00 sec)mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS; + | requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id | + | 1332195 | 1332195 :486 :3 :3 | 1332194 | 1332194 :486 :3 :3 | + 1 row in set , 1 warning (0.00 sec)mysql> SELECT trx_id,trx_state,trx_requested_lock_id,trx_isolation_level FROM INFORMATION_SCHEMA.INNODB_TRX; + | trx_id | trx_state | trx_requested_lock_id | trx_isolation_level | + | 1332195 | LOCK WAIT | 1332195 :486 :3 :3 | REPEATABLE READ | | 1332194 | RUNNING | NULL | REPEATABLE READ | + 2 rows in set (0.00 sec)
Session B 1 2 3 4 5 6 7 8 9 10 11 12 mysql> INSERT INTO t SELECT 11 ; # Timeout ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction mysql> SELECT * FROM t WHERE a= 10 FOR UPDATE ; + | a | + | 10 | + 1 row in set (0.00 sec)mysql> SELECT * FROM t WHERE a= 30 FOR UPDATE ; # Blocked
事务1332194
并不持有聚集索引a
上10
的X Lock
,事务1332195
可以顺利获取聚集索引a
上10
的X Lock
事务1332194
持有聚集索引a
上30
的X Lock
,事务1332195
被阻塞(详细信息见下节)
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS; + | lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data | + | 1332195 :486 :3 :4 | 1332195 | X | RECORD | `test`.`t` | PRIMARY | 486 | 3 | 4 | 30 | | 1332194 :486 :3 :4 | 1332194 | X | RECORD | `test`.`t` | PRIMARY | 486 | 3 | 4 | 30 | + 2 rows in set , 1 warning (0.00 sec)mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS; + | requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id | + | 1332195 | 1332195 :486 :3 :4 | 1332194 | 1332194 :486 :3 :4 | + 1 row in set , 1 warning (0.00 sec)mysql> SELECT trx_id,trx_state,trx_requested_lock_id,trx_isolation_level FROM INFORMATION_SCHEMA.INNODB_TRX; + | trx_id | trx_state | trx_requested_lock_id | trx_isolation_level | + | 1332195 | LOCK WAIT | 1332195 :486 :3 :4 | REPEATABLE READ | | 1332194 | RUNNING | NULL | REPEATABLE READ | + 2 rows in set (0.01 sec)
示意图
RC+Secondary Unique Index+Range
事务隔离级别READ COMMITTED(RC)
存在唯一辅助索引
WHERE
通过RANGE
匹配
表初始化 1 2 3 4 5 6 7 8 9 10 11 mysql> CREATE TABLE t ( - > a INT NOT NULL , - > b INT NOT NULL , - > PRIMARY KEY (a), - > UNIQUE KEY (b) - > ) ENGINE= INNODB CHARSET= LATIN1 ROW_FORMAT= COMPACT; Query OK, 0 rows affected (0.08 sec) mysql> INSERT INTO t VALUES (10 ,20 ),(20 ,50 ),(30 ,10 ),(40 ,40 ),(50 ,30 ); Query OK, 5 rows affected (0.05 sec) Records: 5 Duplicates: 0 Warnings: 0
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 mysql> SET SESSION TX_ISOLATION= 'READ-COMMITTED' ; Query OK, 0 rows affected (0.00 sec) mysql> BEGIN ; Query OK, 0 rows affected (0.00 sec) mysql> SELECT * FROM t WHERE b> 25 AND b< 45 FOR UPDATE ; + | a | b | + | 50 | 30 | | 40 | 40 | + 2 rows in set (0.00 sec)mysql> SELECT trx_id,trx_state,trx_requested_lock_id,trx_isolation_level FROM INFORMATION_SCHEMA.INNODB_TRX; + | trx_id | trx_state | trx_requested_lock_id | trx_isolation_level | + | 1324402 | RUNNING | NULL | READ COMMITTED | + 1 row in set (0.01 sec)
将Session A
的事务隔离级别设置为READ COMMITTED
事务1324402
将获得辅助唯一索引b
上30
、40
的X Lock
,并获得对应的聚集索引a
上50
、40
上的X Lock
Session B 1 2 3 4 5 6 7 mysql> SET SESSION TX_ISOLATION= 'READ-COMMITTED' ; Query OK, 0 rows affected (0.00 sec) mysql> BEGIN ; Query OK, 0 rows affected (0.00 sec) mysql> SELECT * FROM t WHERE b= 30 FOR UPDATE ; # Blocked
将Session B
的事务隔离级别设置为READ COMMITTED
事务1324402
已经持有辅助唯一索引b
上30
的X Lock
,因此会被阻塞(详细信息见下节)
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS; + | lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data | + | 1324403 :405 :4 :6 | 1324403 | X | RECORD | `test`.`t` | b | 405 | 4 | 6 | 30 | | 1324402 :405 :4 :6 | 1324402 | X | RECORD | `test`.`t` | b | 405 | 4 | 6 | 30 | + 2 rows in set , 1 warning (0.01 sec)mysql> select * from information_schema.INNODB_LOCK_WAITS; + | requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id | + | 1324403 | 1324403 :405 :4 :6 | 1324402 | 1324402 :405 :4 :6 | + 1 row in set , 1 warning (0.00 sec)
Session B 1 2 3 4 mysql> SELECT * FROM t WHERE b= 30 FOR UPDATE ; # Timeout ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction mysql> SELECT * FROM t WHERE a= 50 FOR UPDATE ; # Blocked
事务1324402
已经持有聚集索引b
上50
的X Lock
,因此会被阻塞(详细信息见下节)
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS; + | lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data | + | 1324403 :405 :3 :6 | 1324403 | X | RECORD | `test`.`t` | PRIMARY | 405 | 3 | 6 | 50 | | 1324402 :405 :3 :6 | 1324402 | X | RECORD | `test`.`t` | PRIMARY | 405 | 3 | 6 | 50 | + 2 rows in set , 1 warning (0.00 sec)mysql> select * from information_schema.INNODB_LOCK_WAITS; + | requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id | + | 1324403 | 1324403 :405 :3 :6 | 1324402 | 1324402 :405 :3 :6 | + 1 row in set , 1 warning (0.00 sec)
示意图
RR+Secondary Unique Index+Range
事务隔离级别REPEATABLE READ(RR)
存在显式定义唯一辅助索引
WHERE
通过RANGE
匹配
表初始化 1 2 3 4 5 6 7 8 9 10 11 mysql> CREATE TABLE t ( - > a INT NOT NULL , - > b INT NOT NULL , - > PRIMARY KEY (a), - > UNIQUE KEY (b) - > ) ENGINE= INNODB CHARSET= LATIN1 ROW_FORMAT= COMPACT; Query OK, 0 rows affected (0.08 sec) mysql> INSERT INTO t VALUES (10 ,90 ),(20 ,50 ),(30 ,80 ),(40 ,60 ),(50 ,70 ); Query OK, 5 rows affected (0.05 sec) Records: 5 Duplicates: 0 Warnings: 0
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 mysql> SET SESSION TX_ISOLATION= 'REPEATABLE-READ' ; Query OK, 0 rows affected (0.00 sec) mysql> BEGIN ; Query OK, 0 rows affected (0.00 sec) mysql> SELECT * FROM t WHERE b> 55 AND b< 85 FOR UPDATE ; + | a | b | + | 40 | 60 | | 50 | 70 | | 30 | 80 | + 3 rows in set (0.00 sec)mysql> SELECT trx_id,trx_state,trx_requested_lock_id,trx_isolation_level FROM INFORMATION_SCHEMA.INNODB_TRX; + | trx_id | trx_state | trx_requested_lock_id | trx_isolation_level | + | 1324512 | RUNNING | NULL | REPEATABLE READ | + 1 row in set (0.01 sec)
将Session A
的事务隔离级别设置为REPEATABLE READ
事务1324512
将获得唯一辅助索引b
上60
、70
、80
上的X Lock
以及(50,60)
、(60,70)
、(70,80)
上的Gap Lock
,相应地也会获得聚集索引a
上40
、50
、30
的X Lock
依据Next-Key Lock
,事务1324512
将获得唯一辅助索引b
上90
上的X Lock
以及(80,90)
上的Gap Lock
,相应地获得聚集索引a
上10
的X Lock
事务1324512
不会在聚集索引a
上进行Gap Lock
Session B 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 mysql> SET SESSION TX_ISOLATION= 'REPEATABLE-READ' ; Query OK, 0 rows affected (0.00 sec) mysql> BEGIN ; Query OK, 0 rows affected (0.00 sec) mysql> SELECT * FROM t WHERE b= 50 FOR UPDATE ; + | a | b | + | 20 | 50 | + 1 row in set (0.00 sec)mysql> SELECT * FROM t WHERE b= 90 FOR UPDATE ; # Blocked(60 / 70 / 80 blocked too)
将Session B
的事务隔离级别设置为REPEATABLE READ
唯一辅助索引b
上50
尚未被其他事务锁定,事务1324513
可以顺利获得唯一辅助索引b
上50
的X Lock
事务1324512
已持有唯一辅助索引b
上90
的X Lock
,事务1324513
被阻塞(详细信息见下节)
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS; + | lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data | + | 1324513 :410 :4 :2 | 1324513 | X | RECORD | `test`.`t` | b | 410 | 4 | 2 | 90 | | 1324512 :410 :4 :2 | 1324512 | X | RECORD | `test`.`t` | b | 410 | 4 | 2 | 90 | + 2 rows in set , 1 warning (0.00 sec)mysql> select * from information_schema.INNODB_LOCK_WAITS; + | requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id | + | 1324513 | 1324513 :410 :4 :2 | 1324512 | 1324512 :410 :4 :2 | + 1 row in set , 1 warning (0.00 sec)
Session B 1 2 3 4 5 6 7 8 9 10 11 12 mysql> SELECT * FROM t WHERE b= 90 FOR UPDATE ; # Timeout ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction mysql> SELECT * FROM t WHERE a= 20 FOR UPDATE ; + | a | b | + | 20 | 50 | + 1 row in set (0.00 sec)mysql> SELECT * FROM t WHERE a= 10 FOR UPDATE ; # Blocked(40 / 50 / 30 blocked too)
聚集索引a
上20
尚未被其他事务锁定,事务1324513
可以顺利获得聚集索引a
上20
的X Lock
事务1324512
已持有聚集索引a
上10
的X Lock
,事务1324513
被阻塞(详细信息见下节)
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS; + | lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data | + | 1324513 :410 :3 :2 | 1324513 | X | RECORD | `test`.`t` | PRIMARY | 410 | 3 | 2 | 10 | | 1324512 :410 :3 :2 | 1324512 | X | RECORD | `test`.`t` | PRIMARY | 410 | 3 | 2 | 10 | + 2 rows in set , 1 warning (0.00 sec)mysql> select * from information_schema.INNODB_LOCK_WAITS; + | requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id | + | 1324513 | 1324513 :410 :3 :2 | 1324512 | 1324512 :410 :3 :2 | + 1 row in set , 1 warning (0.00 sec)
Session B 1 2 3 4 5 6 7 mysql> SELECT * FROM t WHERE a= 10 FOR UPDATE ; # Timeout ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction mysql> INSERT INTO t VALUES (5 ,45 ); Query OK, 1 row affected (0.00 sec) mysql> INSERT INTO t VALUES (6 ,55 ); # Blocked
唯一聚集索引b
上(-∞,50)
的尚未被其他事务锁定,因此事务1324513
成功插入(5,45)
事务1324512
持有唯一聚集索引b
上(50,60)
的Gap Lock
,因此事务1324513
插入(6,55)
时会被阻塞(详细信息见下节)
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS; + | lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data | + | 1324513 :410 :4 :5 | 1324513 | X,GAP | RECORD | `test`.`t` | b | 410 | 4 | 5 | 60 | | 1324512 :410 :4 :5 | 1324512 | X | RECORD | `test`.`t` | b | 410 | 4 | 5 | 60 | + 2 rows in set , 1 warning (0.00 sec)mysql> select * from information_schema.INNODB_LOCK_WAITS; + | requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id | + | 1324513 | 1324513 :410 :4 :5 | 1324512 | 1324512 :410 :4 :5 | + 1 row in set , 1 warning (0.00 sec)
示意图
RC+Secondary Index+Range
事务隔离级别READ COMMITTED(RC)
存在显式定义非唯一辅助索引
WHERE
通过RANGE
匹配
表初始化 1 2 3 4 5 6 7 8 9 10 11 mysql> CREATE TABLE t ( - > a INT NOT NULL , - > b INT NOT NULL , - > PRIMARY KEY (a), - > KEY (b) - > ) ENGINE= INNODB CHARSET= LATIN1 ROW_FORMAT= COMPACT; Query OK, 0 rows affected (0.08 sec) mysql> INSERT INTO t VALUES (60 ,50 ),(70 ,30 ),(80 ,20 ),(90 ,40 ),(100 ,30 ),(110 ,20 ),(120 ,10 ); Query OK, 7 rows affected (0.01 sec) Records: 7 Duplicates: 0 Warnings: 0
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 mysql> SET SESSION TX_ISOLATION= 'READ-COMMITTED' ; Query OK, 0 rows affected (0.01 sec) mysql> BEGIN ; Query OK, 0 rows affected (0.00 sec) mysql> SELECT * FROM t WHERE b> 15 AND b< 35 FOR UPDATE ; + | a | b | + | 80 | 20 | | 110 | 20 | | 70 | 30 | | 100 | 30 | + 4 rows in set (1.97 sec)mysql> SELECT trx_id,trx_state,trx_requested_lock_id,trx_isolation_level FROM INFORMATION_SCHEMA.INNODB_TRX; + | trx_id | trx_state | trx_requested_lock_id | trx_isolation_level | + | 1324589 | RUNNING | NULL | READ COMMITTED | + 1 row in set (0.01 sec)
将Session A
的事务隔离级别设置为READ COMMITTED
事务1324589
持有辅助索引b
上(b=20,a=80)
、(b=20,a=110)
、(b=30,a=70)
、(b=30,a=100)
的X Lock
,并相应地持有聚集索引a
上(a=80,b=20)
、(a=110,b=20)
、(a=70,b=30)
、(a=100,b=30)
的X Lock
Session B 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 mysql> SET SESSION TX_ISOLATION= 'READ-COMMITTED' ; Query OK, 0 rows affected (0.01 sec) mysql> BEGIN ; Query OK, 0 rows affected (0.00 sec) mysql> SELECT * FROM t WHERE b= 10 FOR UPDATE ; + | a | b | + | 120 | 10 | + 1 row in set (0.02 sec)mysql> SELECT * FROM t WHERE b= 40 FOR UPDATE ; + | a | b | + | 90 | 40 | + 1 row in set (0.00 sec)mysql> SELECT * FROM t WHERE b= 30 FOR UPDATE ; # Blocked
将Session B
的事务隔离级别设置为READ COMMITTED
辅助索引b
上(b=10,a=120)
和(b=40,a=90)
尚未被其他事务锁定,事务1324590
能成功获取辅助索引b
上(b=10,a=120)
和(b=40,a=90)
的X Lock
事务1324589
持有辅助索引b上(b=30,a=70)
的X Lock
,因此事务1324590
被阻塞(详细信息见下节)
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 mysql> select * from information_schema.INNODB_LOCK_WAITS; + | requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id | + | 1324590 | 1324590 :413 :4 :3 | 1324589 | 1324589 :413 :4 :3 | + 1 row in set , 1 warning (0.01 sec)mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS; + | lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data | + | 1324590 :413 :4 :3 | 1324590 | X | RECORD | `test`.`t` | b | 413 | 4 | 3 | 30 , 70 | | 1324589 :413 :4 :3 | 1324589 | X | RECORD | `test`.`t` | b | 413 | 4 | 3 | 30 , 70 | + 2 rows in set , 1 warning (0.01 sec)
Session B 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 mysql> SELECT * FROM t WHERE b= 30 FOR UPDATE ; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction mysql> SELECT * FROM t WHERE a= 120 FOR UPDATE ; + | a | b | + | 120 | 10 | + 1 row in set (0.00 sec)mysql> SELECT * FROM t WHERE a= 90 FOR UPDATE ; + | a | b | + | 90 | 40 | + 1 row in set (0.00 sec)mysql> SELECT * FROM t WHERE a= 100 FOR UPDATE ; # Blocked
聚集索引a
上(a=120,b=10)
和(a=90,b=40)
尚未被其他事务锁定,事务1324590
能成功获取聚集索引a
上(a=120,b=10)
和(a=90,b=40)
的X Lock
事务1324589
持有聚集索引a
上(a=100,b=30)
的X Lock
,因此事务1324590
被阻塞(详细信息见下节)
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 mysql> select * from information_schema.INNODB_LOCK_WAITS; + | requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id | + | 1324590 | 1324590 :413 :3 :6 | 1324589 | 1324589 :413 :3 :6 | + 1 row in set , 1 warning (0.00 sec)mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS; + | lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data | + | 1324590 :413 :3 :6 | 1324590 | X | RECORD | `test`.`t` | PRIMARY | 413 | 3 | 6 | 100 | | 1324589 :413 :3 :6 | 1324589 | X | RECORD | `test`.`t` | PRIMARY | 413 | 3 | 6 | 100 | + 2 rows in set , 1 warning (0.00 sec)
示意图
RR+Secondary Index+Range
事务隔离级别REPEATABLE READ(RR)
存在显式定义非唯一辅助索引
WHERE
通过RANGE
匹配
表初始化 1 2 3 4 5 6 7 8 9 10 11 mysql> CREATE TABLE t ( - > a INT NOT NULL , - > b INT NOT NULL , - > PRIMARY KEY (a), - > KEY (b) - > ) ENGINE= INNODB CHARSET= LATIN1 ROW_FORMAT= COMPACT; Query OK, 0 rows affected (0.08 sec) mysql> INSERT INTO t VALUES (60 ,50 ),(70 ,30 ),(80 ,20 ),(90 ,40 ),(100 ,30 ),(110 ,20 ),(120 ,10 ); Query OK, 7 rows affected (0.01 sec) Records: 7 Duplicates: 0 Warnings: 0
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 mysql> SET SESSION TX_ISOLATION= 'REPEATABLE-READ' ; Query OK, 0 rows affected (0.01 sec) mysql> BEGIN ; Query OK, 0 rows affected (0.00 sec) mysql> SELECT * FROM t WHERE b> 15 AND b< 35 FOR UPDATE ; + | a | b | + | 80 | 20 | | 110 | 20 | | 70 | 30 | | 100 | 30 | + 4 rows in set (1.97 sec)mysql> SELECT trx_id,trx_state,trx_requested_lock_id,trx_isolation_level FROM INFORMATION_SCHEMA.INNODB_TRX; + | trx_id | trx_state | trx_requested_lock_id | trx_isolation_level | + | 1324567 | RUNNING | NULL | REPEATABLE READ | + 1 row in set (0.00 sec)
将Session A
的事务隔离级别设置为REPEATABLE READ
事务1324567
持有辅助索引b
上的X Lock
:(b=20,a=80)
、(b=20,a=110)
、(b=30,a=70)
、(b=30,a=100)
事务1324567
持有辅助索引b
上的Gap Lock
:(b=10,a=120)~(b=20,a=80)
、(b=20,a=80)~(b=20,a=110)
、(b=20,a=110)~(b=30,a=70)
、(b=30,a=70)~(b=30,a=100)
事务1324567
持有聚集索引a
上的X Lock
:(a=80,b=20)
、(a=110,b=20)
、(a=70,b=30)
、(a=100,b=30)
依据Next-Key Lock
, 事务1324567
还持有辅助索引b
上(b=40,a=90)
的X Lock
和(b=30,a=100)~(b=40,a=90)
上的Gap Lock
,并相应地持有聚集索引a
上(a=90,b=40)
的X Lock
Session B 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 mysql> SET SESSION TX_ISOLATION= 'REPEATABLE-READ' ; Query OK, 0 rows affected (0.01 sec) mysql> BEGIN ; Query OK, 0 rows affected (0.00 sec) mysql> SELECT * FROM t WHERE b= 10 FOR UPDATE ; + | a | b | + | 120 | 10 | + 1 row in set (0.02 sec)mysql> SELECT * FROM t WHERE b= 40 FOR UPDATE ; # Blocked
将Session B
的事务隔离级别设置为REPEATABLE READ
辅助索引b
上(b=10,a=120)
尚未被其他事务锁定,事务1324568
能成功获取辅助索引b
上(b=10,a=120)
的X Lock
事务1324567
持有辅助索引b
上(b=40,a=90)
的X Lock
,因此事务1324568
被阻塞(详细信息见下节)
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS; + | lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data | + | 1324568 :412 :4 :5 | 1324568 | X | RECORD | `test`.`t` | b | 412 | 4 | 5 | 40 , 90 | | 1324567 :412 :4 :5 | 1324567 | X | RECORD | `test`.`t` | b | 412 | 4 | 5 | 40 , 90 | + 2 rows in set , 1 warning (0.03 sec)mysql> select * from information_schema.INNODB_LOCK_WAITS; + | requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id | + | 1324568 | 1324568 :412 :4 :5 | 1324567 | 1324567 :412 :4 :5 | + 1 row in set , 1 warning (0.00 sec)
Session B 1 2 3 4 5 6 7 8 9 10 11 12 mysql> SELECT * FROM t WHERE b= 40 FOR UPDATE ; # Timout ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction mysql> SELECT * FROM t WHERE a= 120 FOR UPDATE ; + | a | b | + | 120 | 10 | + 1 row in set (0.00 sec)mysql> SELECT * FROM t WHERE a= 90 FOR UPDATE ; # Blocked
聚集索引a
上(a=120,b=10)
尚未被其他事务锁定,事务1324568
能成功获取聚集索引a
上(a=120,b=10)
的X Lock
事务1324567
持有聚集索引a
上(a=90,b=40)
的X Lock
,因此事务1324568
被阻塞(详细信息见下节)
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 mysql> select * from information_schema.INNODB_LOCK_WAITS; + | requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id | + | 1324568 | 1324568 :412 :3 :5 | 1324567 | 1324567 :412 :3 :5 | + 1 row in set , 1 warning (0.01 sec)mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS; + | lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data | + | 1324568 :412 :3 :5 | 1324568 | X | RECORD | `test`.`t` | PRIMARY | 412 | 3 | 5 | 90 | | 1324567 :412 :3 :5 | 1324567 | X | RECORD | `test`.`t` | PRIMARY | 412 | 3 | 5 | 90 | + 2 rows in set , 1 warning (0.00 sec)
Session B 1 2 3 4 5 6 7 mysql> SELECT * FROM t WHERE a= 90 FOR UPDATE ; # Timeout ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction mysql> INSERT INTO t VALUES (95 ,40 ); Query OK, 1 row affected (0.01 sec) mysql> INSERT INTO t VALUES (75 ,20 ); # Blocked
辅助索引b
上(b=40,a=90)~(b=50,a=60)
不存在Gap Lock
,事务1324568
能成功插入(a=95,b=40)
事务1324567
持有辅助索引b
上(b=10,a=120)~(b=20,a=80)
的Gap Lock
,事务1324568
插入(a=75,b=20)
被阻塞(详细信息见下节)
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS; + | lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data | + | 1324568 :412 :4 :4 | 1324568 | X,GAP | RECORD | `test`.`t` | b | 412 | 4 | 4 | 20 , 80 | | 1324567 :412 :4 :4 | 1324567 | X | RECORD | `test`.`t` | b | 412 | 4 | 4 | 20 , 80 | + 2 rows in set , 1 warning (0.00 sec)mysql> select * from information_schema.INNODB_LOCK_WAITS; + | requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id | + | 1324568 | 1324568 :412 :4 :4 | 1324567 | 1324567 :412 :4 :4 | + 1 row in set , 1 warning (0.00 sec)
Session B 1 2 3 4 mysql> INSERT INTO t VALUES (75 ,20 ); # Timeout ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction mysql> INSERT INTO t VALUES (115 ,20 ); # Blocked
事务1324567
持有辅助索引b
上(b=20,a=110)~(b=30,a=70)
的Gap Lock
,事务1324568
插入(a=115,b=20)
被阻塞(详细信息见下节)
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS; + | lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data | + | 1324568 :412 :4 :3 | 1324568 | X,GAP | RECORD | `test`.`t` | b | 412 | 4 | 3 | 30 , 70 | | 1324567 :412 :4 :3 | 1324567 | X | RECORD | `test`.`t` | b | 412 | 4 | 3 | 30 , 70 | + 2 rows in set , 1 warning (0.00 sec)mysql> select * from information_schema.INNODB_LOCK_WAITS; + | requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id | + | 1324568 | 1324568 :412 :4 :3 | 1324567 | 1324567 :412 :4 :3 | + 1 row in set , 1 warning (0.00 sec)
示意图
在RR
隔离级别下,类似SELECT ... FOR UPDATE
这种Current Read
,使用Gap Lock
能保证过滤出来的范围不被其他事务插入新的记录,防止幻读
的产生
RC+No Index 表初始化 1 2 3 4 5 6 7 8 9 10 mysql> CREATE TABLE t ( - > a INT NOT NULL , - > b INT NOT NULL , - > PRIMARY KEY (a) - > ) ENGINE= INNODB CHARSET= LATIN1 ROW_FORMAT= COMPACT; Query OK, 0 rows affected (0.08 sec) mysql> INSERT INTO t VALUES (10 ,50 ),(20 ,60 ),(30 ,70 ),(40 ,80 ),(50 ,90 ); Query OK, 5 rows affected (0.02 sec) Records: 5 Duplicates: 0 Warnings: 0
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 mysql> SET SESSION TX_ISOLATION= 'READ-COMMITTED' ; Query OK, 0 rows affected (0.00 sec) mysql> BEGIN ; Query OK, 0 rows affected (0.00 sec) mysql> SELECT * FROM t WHERE b= 70 OR b= 90 FOR UPDATE ; + | a | b | + | 30 | 70 | | 50 | 90 | + 2 rows in set (0.01 sec)mysql> SELECT trx_id,trx_state,trx_requested_lock_id,trx_isolation_level FROM INFORMATION_SCHEMA.INNODB_TRX; + | trx_id | trx_state | trx_requested_lock_id | trx_isolation_level | + | 1324624 | RUNNING | NULL | READ COMMITTED | + 1 row in set (0.00 sec)
将Session A
的事务隔离级别设置为READ COMMITTED
由于列b上无索引
,只能通过聚集索引a
进行全表扫描
,事务1324624
将持有聚集索引a
上30
、50
的X Lock
Session B 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 mysql> SET SESSION TX_ISOLATION= 'READ-COMMITTED' ; Query OK, 0 rows affected (0.00 sec) mysql> BEGIN ; Query OK, 0 rows affected (0.00 sec) mysql> SELECT * FROM t WHERE a= 10 FOR UPDATE ; + | a | b | + | 10 | 50 | + 1 row in set (0.00 sec)mysql> SELECT * FROM t WHERE a= 20 FOR UPDATE ; + | a | b | + | 20 | 60 | + 1 row in set (0.00 sec)mysql> SELECT * FROM t WHERE a= 40 FOR UPDATE ; + | a | b | + | 40 | 80 | + 1 row in set (0.00 sec)mysql> SELECT * FROM t WHERE a= 30 FOR UPDATE ; # Blocked
聚集索引a
上的10
、20
、40
并未被其他事务锁定,事务1324625
能成功获取它们的X Lock
事务1324624
持有聚集索引a
上的30
的X lock
,事务1324625
被阻塞(详细信息见下节)
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 mysql> select * from information_schema.INNODB_LOCK_WAITS; + | requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id | + | 1324625 | 1324625 :414 :3 :4 | 1324624 | 1324624 :414 :3 :4 | + 1 row in set , 1 warning (0.00 sec)mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS; + | lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data | + | 1324625 :414 :3 :4 | 1324625 | X | RECORD | `test`.`t` | PRIMARY | 414 | 3 | 4 | 30 | | 1324624 :414 :3 :4 | 1324624 | X | RECORD | `test`.`t` | PRIMARY | 414 | 3 | 4 | 30 | + 2 rows in set , 1 warning (0.00 sec)
Session B 1 2 3 4 mysql> SELECT * FROM t WHERE a= 30 FOR UPDATE ; # Timeout ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction mysql> SELECT * FROM t WHERE a= 50 FOR UPDATE ; # Blocked
事务1324624
持有聚集索引a
上的50
的X lock
,事务1324625
被阻塞(详细信息见下节)
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS; + | lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data | + | 1324625 :414 :3 :6 | 1324625 | X | RECORD | `test`.`t` | PRIMARY | 414 | 3 | 6 | 50 | | 1324624 :414 :3 :6 | 1324624 | X | RECORD | `test`.`t` | PRIMARY | 414 | 3 | 6 | 50 | + 2 rows in set , 1 warning (0.00 sec)mysql> select * from information_schema.INNODB_LOCK_WAITS; + | requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id | + | 1324625 | 1324625 :414 :3 :6 | 1324624 | 1324624 :414 :3 :6 | + 1 row in set , 1 warning (0.00 sec)
示意图
RR+No Index 表初始化 1 2 3 4 5 6 7 8 9 10 mysql> CREATE TABLE t ( - > a INT NOT NULL , - > b INT NOT NULL , - > PRIMARY KEY (a) - > ) ENGINE= INNODB CHARSET= LATIN1 ROW_FORMAT= COMPACT; Query OK, 0 rows affected (0.08 sec) mysql> INSERT INTO t VALUES (10 ,50 ),(20 ,60 ),(30 ,70 ),(40 ,80 ),(50 ,90 ); Query OK, 5 rows affected (0.02 sec) Records: 5 Duplicates: 0 Warnings: 0
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 mysql> SET SESSION TX_ISOLATION= 'REPEATABLE-READ' ; Query OK, 0 rows affected (0.00 sec) mysql> BEGIN ; Query OK, 0 rows affected (0.00 sec) mysql> SELECT * FROM t WHERE b= 70 FOR UPDATE ; + | a | b | + | 30 | 70 | + 1 row in set (0.01 sec)mysql> SELECT trx_id,trx_state,trx_requested_lock_id,trx_isolation_level FROM INFORMATION_SCHEMA.INNODB_TRX; + | trx_id | trx_state | trx_requested_lock_id | trx_isolation_level | + | 1324610 | RUNNING | NULL | REPEATABLE READ | + 1 row in set (0.00 sec)
将Session A
的事务隔离级别设置为REPEATABLE READ
由于列b上无索引
,只能通过聚集索引a
进行全表扫描
,事务1324610
将持有聚集索引a
上10
、20
、30
、40
、50
的X Lock
,并持有聚集索引a
上(-∞,10)
、(10,20)
、(20,30)
、(30,40)
、(40,50)
、(50,+∞)
上的Gap Lock
Session B 1 2 3 4 5 6 7 mysql> SET SESSION TX_ISOLATION= 'REPEATABLE-READ' ; Query OK, 0 rows affected (0.00 sec) mysql> BEGIN ; Query OK, 0 rows affected (0.00 sec) mysql> INSERT INTO t VALUES (5 ,100 ); # Blocked
事务1324610
持有聚集索引a
上(negative infinity,10)
的Gap Lock
,事务1324611
插入(5,100)
被阻塞(详细信息见下节)
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS; + | lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data | + | 1324611 :414 :3 :2 | 1324611 | X,GAP | RECORD | `test`.`t` | PRIMARY | 414 | 3 | 2 | 10 | | 1324610 :414 :3 :2 | 1324610 | X | RECORD | `test`.`t` | PRIMARY | 414 | 3 | 2 | 10 | + 2 rows in set , 1 warning (0.00 sec)mysql> select * from information_schema.INNODB_LOCK_WAITS; + | requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id | + | 1324611 | 1324611 :414 :3 :2 | 1324610 | 1324610 :414 :3 :2 | + 1 row in set , 1 warning (0.00 sec)
Session B 1 2 3 4 mysql> INSERT INTO t VALUES (5 ,100 ); # Timeout ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction mysql> INSERT INTO t VALUES (25 ,100 ); # Blocked
事务1324610
持有聚集索引a
上(20,30)
的Gap Lock
,事务1324611
插入(25,100)
被阻塞(详细信息见下节)
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 mysql> select * from information_schema.INNODB_LOCK_WAITS; + | requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id | + | 1324611 | 1324611 :414 :3 :4 | 1324610 | 1324610 :414 :3 :4 | + 1 row in set , 1 warning (0.00 sec)mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS; + | lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data | + | 1324611 :414 :3 :4 | 1324611 | X,GAP | RECORD | `test`.`t` | PRIMARY | 414 | 3 | 4 | 30 | | 1324610 :414 :3 :4 | 1324610 | X | RECORD | `test`.`t` | PRIMARY | 414 | 3 | 4 | 30 | + 2 rows in set , 1 warning (0.01 sec)
Session B 1 2 3 4 mysql> INSERT INTO t VALUES (25 ,100 ); # Timeout ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction mysql> INSERT INTO t VALUES (55 ,100 ); # Blocked
+∞
即supremum pseudo-record
,相关信息请参照「InnoDB备忘录 - 数据页格式」
事务1324610
持有聚集索引a
上(50,+∞)
的Gap Lock
,事务1324611
插入(55,100)
被阻塞(详细信息见下节)
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS; + | lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data | + | 1324611 :414 :3 :1 | 1324611 | X | RECORD | `test`.`t` | PRIMARY | 414 | 3 | 1 | supremum pseudo- record | | 1324610 :414 :3 :1 | 1324610 | X | RECORD | `test`.`t` | PRIMARY | 414 | 3 | 1 | supremum pseudo- record | + 2 rows in set , 1 warning (0.00 sec)mysql> select * from information_schema.INNODB_LOCK_WAITS; + | requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id | + | 1324611 | 1324611 :414 :3 :1 | 1324610 | 1324610 :414 :3 :1 | + 1 row in set , 1 warning (0.00 sec)
Session B 1 2 3 4 mysql> INSERT INTO t VALUES (55 ,100 ); # Timeout ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction mysql> SELECT * FROM t WHERE a= 50 FOR UPDATE ; # Blocked
事务1324610
持有聚集索引a
上50
的X Lock
,事务1324611
被阻塞(详细信息见下节)
Session A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 mysql> select * from information_schema.INNODB_LOCK_WAITS; + | requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id | + | 1324611 | 1324611 :414 :3 :6 | 1324610 | 1324610 :414 :3 :6 | + 1 row in set , 1 warning (0.00 sec)mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS; + | lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data | + | 1324611 :414 :3 :6 | 1324611 | X | RECORD | `test`.`t` | PRIMARY | 414 | 3 | 6 | 50 | | 1324610 :414 :3 :6 | 1324610 | X | RECORD | `test`.`t` | PRIMARY | 414 | 3 | 6 | 50 | + 2 rows in set , 1 warning (0.00 sec)
示意图
参考资料
MySQL技术内幕 - InnoDB存储引擎 V2
MySQL 加锁处理分析
InnoDB Locking
The INFORMATION_SCHEMA INNODB_TRX Table
The INFORMATION_SCHEMA INNODB_LOCKS Table
The INFORMATION_SCHEMA INNODB_LOCK_WAITS Tabl