MySQL有哪些隔离级别?每种可能会产生什么问题? 什么是幻读? InnoDB在RR隔离级别下会出现幻读吗? 幻读如何解决?
MySQL隔离级别在上一篇具体有介绍到,所以我们具体来聊一聊可能产生的问题。
可能会产生 脏读 :事务A修改了一条记录,但是还没有提交,随后事务B读取了这条记录,然后事务A发生了Rollback,此时事务B读取到的数据就是脏数据。
可能会产生 不可重复读 :事务A在同一个事物内多次读取了同一条数据,在俩次读取之间事务B修改了这条数据并提交了事务,导致事务A俩次读取到的数据不一致。
这宗隔离级别解决了所有可能发生的问题,但是性能比较差,它通过轻质事务排序,给每一条数据都加上了锁,会导致超时或者大量抢锁的现象。
可能产生 幻读
在同一个事务内,多次执行同一个范围查询,由于其它事务插入新的数据并提交了事务,导致后续查询到了之前没有出现的记录
事务A执行了 SELECT * FROM user WHERE age >= 18; 此时假设查询出来了 3 条记录,此时事务B,插入了一条记录age=20并提交了数据,之后事务A再次查询,发现比之前查询的结果多了提交记录,此时就产生了幻读。

RR隔离级别在很大程度上解决了幻读,但并没有完全消除它。
如果是普通的快照读,它利用MVCC机制,就像给数据拍了个快照,不管怎么插入新数据,查询到的始终是事务刚开始那一刻的状态。
如果是当前读,这时候InnoDB会使用间隙锁。它不仅会锁住现有记录,还会吧记录之间的坑也占了,让别人无法往这个范围内插数据,从源头上把”幻影“给堵住了。
当事务A查询了一条id为5的数据,没有查询到,然后事务B插入了新数据并提交了事务,随后事务A update 更新了id为5的数据,更新成功了(由于update是当前读,所以它能够读取到别的事务提交最新的数据),一旦更新成功这条数据的DB_TRX_ID就会变为事务A的,之后事务A再次查询这条id为5的这条记录,就能够查询到了,此时就发生了幻读。
MVCC规定了自己修改的数据,自己可见

事务A使用普通SELECT查询了这条数据没有查询到,事务B插入并提交,之后事务A改用当前读再查一遍,此时就能读取到事务B插入的数据,产生了幻读。


对于普通查询,MySQL依靠MVCC机制通过读取历史快照解决了幻读。
对于写操作或加锁查询,MySQL依靠Next-Key-Locks(间隙锁+行锁)把可能插入数据的“间隙”锁死了,防止幻影记录的出现。