前言:
在上篇里分析了一次mysql死锁问题,后来又深入研究了下死锁的其他场景,innodb间隙锁场景下也可能会发生死锁,所以进一步巩固下间隙锁的知识
1.gap就是索引树中插入新记录的空隙
2.相应的gap锁就是加在gap上的锁
防止幻读,通过间隙锁阻止特定条件的新记录的插入,后面单独就那些验证幻读现象
1. 只在REPEATABLE READ隔离级别下的特定操作才会取得gap lock
2. UPDATE/DELETE/SELECT FOR UPDATE时,除了对唯一索引的唯一搜索外都会获取gap锁,也就是说主键或唯一索引的搜索不会获取间隙锁,当然如果查询条件还包含非唯一索引,那么还是会获取间隙锁
1.创建表:
CREATE TABLE `test_gap_table` (
`primary_no` char(16) NOT NULL COMMENT '主键号',
`index_no` char(16) NOT NULL COMMENT '索引号',
PRIMARY KEY (`primary_no`),
key(`index_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='测试间隙表';
2.插入测试数据:
INSERT INTO `test_gap_table` VALUES ('1', 'a');
INSERT INTO `test_gap_table` VALUES ('3', 'c');
INSERT INTO `test_gap_table` VALUES ('5', 'd');
INSERT INTO `test_gap_table` VALUES ('7', 'e');
##开启事务1
START TRANSACTION;
## 获取间隙锁,锁定范围(a,d)
UPDATE test_gap_table SET index_no='c' where index_no='c';
## 休息10秒,执行事务2
SELECT SLEEP(10);
## 执行insert,插入到事务2的间隙锁锁定范围中
INSERT INTO test_gap_table(primary_no, index_no) VALUES('7', 'e');
##开启事务2
START TRANSACTION;
## 获取间隙锁,锁定范围(d, d后面的无穷大)
UPDATE test_gap_table SET index_no='e' where index_no='e';
## 执行insert,插入到事务1的间隙锁锁定范围中
INSERT INTO test_gap_table(primary_no, index_no) VALUES('2', 'b');
1.创建表:
CREATE TABLE `test_rr_unreal` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`index_no` int(10) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
2.插入数据:
INSERT INTO `test_rr_unreal` VALUES ('1', '100');
3.在mysql命令行下开启一个事务A,执行查询操作:
4.在mysql命令行下开启另一个session,执行更新操作:
5.在事务A下,执行更新操作:
6.在事务A下,执行查询操作:
在事务A中,预期是基于查询结果101,但是被另一个事务的更新操作影响到了最终预期结果,违反了REPEATABLE READ的承诺,看到了事务开始后其它事务的并发更新,出现幻读。
虽然rr隔离级别下看到的是事务开始时的快照,在update/delete操作下,是可以看到另一个事务提交的操作的。