Mysql的事务隔离级别

MySQL InnoDB 幻读_innodb

这四种隔离级别,当存在多个事务并发冲突的时候,可能会出现脏读,不可重复读,幻读的一些问题,而innoDB在可重复读隔离级别模式下解决了幻读的一个问题,

什么是幻读

幻读是指在同一个事务中,前后两次查询相同范围的时候得到的结果不一致

MySQL InnoDB 幻读_innodb_02

如图,第一个事务里面,我们执行一个范围查询,这个时候满足条件的数据只有一条,而在第二个事务里面,它插入一行数据并且进行了提交,接着第一个事务再去查询的时候,得到的结果比第一次查询的结果多出来一条数据,注意第一个事务的第一次和第二次查询,都在同一个事物里面,所以,幻读会带来数据一致性的问题

InnoDB如何解决幻读的问题

InnoDB引入​​间隙锁​​​和​​next-key lock​​机制去解决幻读问题

MySQL InnoDB 幻读_加锁_03

假如现在存在这样一个B+Tree的索引结构,这个结构有4个索引元素,分别是1,4,7,10 当我们通过主键索引查询一条记录,并且对这条记录通过​​for update​​加锁的时候

SELECT*FROM user WHERE id =1 FOR UPDATE;

这个时候会产生一个记录锁,也就是行锁,锁定​​id=1​​这个索引

MySQL InnoDB 幻读_加锁_04

被锁定的记录在锁释放之前,其他事务无法对这一条记录做任何操作的,前面我们所过对幻读的定义,幻读是指在同一个事务中,前后两次查询相同范围的时候得到的结果不一致,注意这里敲掉的是范围查询,也就是说要解决幻读的问题,必须保证一个点

SELECT*FROM user WHERE id>4 FOR UPDATE;

就是如果一个事务通过这样一条语句进行锁定的时候,另外一个事务再执行

INSERT INTOI user( id,name) VALUES(5, 'mimi' );

这样一条insert语句需要被阻塞,直到前面获得所的事务被释放,所以在innonDB设计一种​​间隙锁​​,它的主要功能是锁定一定范围内的索引记录

MySQL InnoDB 幻读_加锁_05

当对查询范围​​id > 4 and id < 7​​​这个范围加锁的时候,会针对B+数中(4,7)这个开区间的范围加​​间隙锁​​,意味着在这种情况下其他事务对这个区间的数据进行插入更新删除都会被锁住,但是还有另外一种情况,比如像这样

SELECT*FROM user WHERE id>4 FOR UPDATE;

这条查询语句针对​​id > 4这​​​个条件加锁,那么它需要锁定多个索引区间,所以这个情况下InnoDB引入一个叫​​next-key lock​​​机制,​​next-key lock​​​相当于间隙锁和记录锁的合集,记录锁锁定存在记录的行,间隙锁锁住的是记录行之间的间隙,而​​next-key lock​​锁住的是两者的和

MySQL InnoDB 幻读_innodb_06

每个数据行非唯一的索引列,都会存在一把​​next-key lock​​​,当某个事务持有这一行数据的​​next-key lock​​​的时候,会锁住一段在左开右闭区间的数据,因此当通过​​id > 4​​​这样一个范围加锁的时候,InnoDB会去加一个​​next-key lock​​​锁,锁定的区间范围是(4,7 ](7,10 ](10,+♾️ ]。间隙锁和​​next-key lock​​​的区别是在加锁的范围,​​间隙锁​​​锁定的是两个索引之间的间隙,而​​next-key lock​​​会锁定多个索引区间,它包含​​记录锁​​​和​​间隙锁​​​当我们使用范围查询不仅仅命中Record记录,还包含了Gap间隙的时候,在这种情况下使用的就是临键锁,也就是​​next-key lock​​它是Mysql里面默认的行锁算法