Mysql怎么解决幻读问题(innoDB)

幻读:在一个事务中,第一次读取的行数和第二次读取的行数不一致。可以见到别的事务新插入的行,并且得是已提交的事务

在隔离级别定义中,可重复读级别下是解决不了幻读的。所有innoDB引入了锁机制解决。

要知道可重复读级别的实现是MVCC。

对于快照读,也就是处于事务中的读来说。只能见到开启事务的一刻数据库的数据状态。另外一个事务新插入的行也是不可见的。

实验DEMO,5.7版本的

快照读下,部分解决幻读问题

mysql产生幻读的隔离级别 mysql怎么解决幻读的_mysql产生幻读的隔离级别

数据和索引,id为主键索引

事务A第一次快照读下查询数据为6条,注意begin;只有在运行了第一条sql之后才会开启事务。不是说一执行begin就开启

mysql产生幻读的隔离级别 mysql怎么解决幻读的_加锁_02

事务B插入一行之后查询行数为7

mysql产生幻读的隔离级别 mysql怎么解决幻读的_数据库_03

事务A快照读下依旧为6

mysql产生幻读的隔离级别 mysql怎么解决幻读的_mysql_04

结论:快照读下可以部分解决幻读问题。但是如果在事务A中执行update语句涉及到了新插入的行。

mysql产生幻读的隔离级别 mysql怎么解决幻读的_database_05

在事务A中执行上图语句,会涉及到新插入的4,4,4一行。此时事务A再次查询行数,如下图已经变成了7条。所以说是部分解决。

mysql产生幻读的隔离级别 mysql怎么解决幻读的_加锁_06

当前读依靠行锁解决

实验DEMO

依靠行锁解决:在当前读下会对行加锁,其它事务就不能新插入行,只有当前事务锁释放后才可插入。

加行锁的基本单位是next-key lock 临键锁 锁的范围是 左开右闭

sql:
	select * from t where id = 5 for update;
	加锁范围: (0,5] 等值唯一查询 加锁退化为行锁,只锁5 
	selec * from t for update;
	锁住全表
	(0,5],(5,10],(10,15],(15,20],(20,25],(25,+无穷],

注意得是可重复读级别下。

事务A当前读

mysql产生幻读的隔离级别 mysql怎么解决幻读的_mysql产生幻读的隔离级别_07

事务B插入

mysql产生幻读的隔离级别 mysql怎么解决幻读的_database_08