0x01 测试环境
操作系统:centos7
数据库版本:mysql 5.7.19
存储引擎:innodb
隔离级别:Repeatable Read
表定义语句:
CREATE TABLE `tuser` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(12) DEFAULT NULL,
`test` bigint(20) NOT NULL,
`remark` varchar(24) DEFAULT NULL,
`createtime` datetime DEFAULT NULL,
`updatetime` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_heihei` (`test`)
) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=utf8
索引:test列。
0x02 第一个测试步骤
- 向表中插入10000条数据。
- set autocommit=0;
- 开启两个事务
-
第一个事务执行
update tuser set name='xxx' where test > 5000;
-
第二个事务执行
insert into tuser (id, name, test) values (10001, 'xxx', 5001);
-
查询information_schema.INNODB_LOCKS可见
*************************** 1. row *************************** lock_id: 96279:150:76:1 lock_trx_id: 96279 lock_mode: X lock_type: RECORD lock_table: `test_batch`.`tuser` lock_index: PRIMARY lock_space: 150 lock_page: 76 lock_rec: 1 lock_data: supremum pseudo-record *************************** 2. row *************************** lock_id: 96278:150:76:1 lock_trx_id: 96278 lock_mode: X lock_type: RECORD lock_table: `test_batch`.`tuser` lock_index: PRIMARY lock_space: 150 lock_page: 76 lock_rec: 1 lock_data: supremum pseudo-record 2 rows in set, 1 warning (0.00 sec)
lock_data的值为supremum pseudo-record,这代表比索引中所有值都大,但却不存在索引中,相当于最后一行之后的gap lock。
0x03 第二个测试步骤
- 向表中插入10000条数据。
- set autocommit=0;
- 开启两个事务
-
第一个事务执行
update tuser set name='xxx' where test = 5000;
-
第二个事务执行
insert into tuser (id, name, test) values (10001, 'xxx', 5000);
-
查询information_schema.INNODB_LOCKS可见
*************************** 1. row *************************** lock_id: 96283:150:52:626 lock_trx_id: 96283 lock_mode: X,GAP lock_type: RECORD lock_table: `test_batch`.`tuser` lock_index: idx_test lock_space: 150 lock_page: 52 lock_rec: 626 lock_data: 5001, 5002 *************************** 2. row *************************** lock_id: 96281:150:52:626 lock_trx_id: 96281 lock_mode: X,GAP lock_type: RECORD lock_table: `test_batch`.`tuser` lock_index: idx_test lock_space: 150 lock_page: 52 lock_rec: 626 lock_data: 5001, 5002 2 rows in set, 1 warning (0.00 sec)
可以看到lock_mode为__X,Gap__,这代表了update语句拿到了5000的gap锁。
0x03 第三个测试步骤
- 向表中插入10000条数据。
- set autocommit=0;
- 开启两个事务
-
第一个事务执行
update tuser set name='xxx' where test > 5001;
-
第二个事务执行
insert into tuser (id, name, test) values (NULL, 'xxx', 5001);
-
查询information_schema.INNODB_LOCKS可见
*************************** 1. row *************************** lock_id: 249524:278:4:3 lock_trx_id: 249524 lock_mode: X,GAP lock_type: RECORD lock_table: `test`.`tuser` lock_index: idx_heihei lock_space: 278 lock_page: 4 lock_rec: 3 lock_data: 5002, 2 *************************** 2. row *************************** lock_id: 249520:278:4:3 lock_trx_id: 249520 lock_mode: X lock_type: RECORD lock_table: `test`.`tuser` lock_index: idx_heihei lock_space: 278 lock_page: 4 lock_rec: 3 lock_data: 5002, 2
可以看到事务一拿到了Next-Key Lock锁,而事务二只拿了X锁。