数据库的事务隔离级别是一个老生常谈的话题。早在ANSISQL-92标准里,基于对3种“怪象”(phenomena)的避免的能力,定义了四种级别:
?READ-UNCOMMITTED:未定义,在[CASIL]论文中引入了避免脏写(dirty-write)这一条
?READ-COMMITTED:避免脏读(dirty-read)
?REPEATABLE-READ:避免不可重复读
?SERIALIZABLE:避免幻读(phantom-read)
这四种隔离级别在我们讨论数据库事务的时候常常被当成标准答案。
我们也常常在阅读数据库并发控制相关的话题时,听到读写锁这个概念。再在后来阅读MySQL之类的数据库文档时,听到快照对于读写锁的并发性优化这个话题。
本文将探讨这两把锁和快照机制是如何作用于事务隔离级别的。通过阅读本文,我们也会发现,基于锁和快照实现的事务隔离级别其实不止上述四种,“怪象”也不仅仅是上述四种。
1ANSISQL-92到底在说什么
ANSISQL-92作为一个不关心如何实现的标准,它的责任是给出定义。而它定义事务隔离级别的方法就是看一个数据库的实现是不是成功的避免了某些“怪象”,根据实现能避免多少种“怪象”来判定它做到了什么级别的隔离性。
我们有3个假设:
?在SQL-92的语境下共享数据只有一份
?回滚的意思就是让数据回到本事务修改前的值
?由于只有一份,回滚的实现基于这样的办法:事务每次修改一个共享数据,本事务都会记住这个数据在修改之前的值,以便回滚时把它设置回去
怪象到隔离性的关系已在本文开头叙述了,这里只讲讲上文提到的4个“怪象”是什么意思。
1.1脏写
某个事务对数据x做了写入操作,在本事务结束前,另一个事务也对x做了写操作。
怎么就脏了?试想两个场景。
1.1.1脏写场景1
假设有个一致性约束叫做数据x必须等于数据y。两个并发的事务都按照这个约束去写数据,时序如下:
示例中的两个都事务逻辑都在保证x=y(一个打算让x=y=1,另一个打算让x=y=2),但是最终提交后,x=2,y=1,不满足x=y的约束了。
1.1.2脏写场景2
场景2的约束更简单:只要修改x,它就必须被修改成2