前言
遥想2019年,准备校招面试过程中背"八股文",背了这样一个知识点:数据库事务隔离级别有 读未提交、读已提交、可重复读、串行化。其中,读已提交能解决脏读问题;可重复读能解决脏读、不可重复读问题;串行化能解决脏读、不可重复读、幻读问题。
这个知识点一直记在了脑海里,没有去更深入的理解。
近日在学习过程中,发现【可重复读】的事务隔离级别也可以避免幻读的发生,故此记录。
拨开云雾
以下内容摘自《MySQL技术内幕:InnoDB存储引擎》p269
在默认的事务隔离级别下,REPEATABLE READ下,InnoDB存储引擎采用Next-Key Locking机制来避免幻读问题。这点可能不同于其他的数据库如Oracle数据库,因为其可能需要SERILIZABLE的事务隔离级别下才能解决幻读问题。
幻读问题是指在同一事务下,连续执行两次同样的SQL语句可能导致不同的结果,第二次的SQL语句可能会返回之前不存在的行。下面将演示该例子,表t由1、2、5这三个值组成,若这时事务T1执行如下的SQL语句:select * from t where a > 2 for update; 注意这时事务T1并没有进行提交操作,上述应该返回5这个结果。若与此同时另一个事务T2插入了4这个值,并且数据库允许该操作,那么事务T1再次执行上述SQL语句会得到结果4和5。这与第一次得到的结果不同,违反了事务的隔离性,即当前事务能够看到其他事务的结果。
InnoDB存储引擎采用Next-Key Locking算法避免幻读问题。对于上述的SQL语句,其锁住的不是5这单个值,而是对(2,正无穷大)这个范围加了X锁。因此任何对于这个范围的插入都是不被允许的,从而避免幻读。
InnoDB存储引擎默认的事务隔离级别是可重复读,在该隔离级别下,其采用Next-Key Locking的方式来加锁。(读者备注:因此不会出现幻读问题,上面讲的例子在该隔离级别下,不会复现) 而在事务隔离级别【读已提交】下,其仅采用 Record Lock,因此在上述的示例中,会话A需要将事务的隔离级别设置为读已提交。
接着上面的内容做个拓展,讲一下 InnoDB存储引擎【行锁】的3种算法,主体内容还是来自书籍《MySQL技术内幕:InnoDB存储引擎》p265
行锁的3种算法
Record Lock:单个行记录上的锁
Gap Lock:间隙锁,锁定一个范围,但不包含记录本身
Next-Key Lock:Gap Lock+Record Lock,锁定一个范围,且锁定记录本身
Record Lock总是会去锁住索引记录,如果InnoDB存储引擎表在建立的时候没有设置任何一个索引,那么这时InnoDB存储引擎会使用隐式的主键来进行锁定。
Next-Key Lock是结合了Gap Lock和Record Lock的一种锁定算法,在Next-Key Lock算法下,InnoDB对于行的查询都是采用这种锁定算法。
采用Next-Key Lock的锁定技术称为Next-Key Locking。其设计的目的是为了解决虚读/幻读问题,锁定的是一个范围。
当查询的索引含有唯一属性时,InnoDB存储引擎会对Next-Key Lock进行优化,将其降级为Record Lock,即仅锁住索引本身而不是范围,从而提高应用的并发性。
总结
技术还是要加以实践啊,之前校招为了找工作,背了很多知识点,但没有真正吃透。想要真正掌握知识,还是需要有自己理解的。