数据库相对于其它存储软件一个核心的特征是它支持事务,所谓事务的ACID就是原子性,一致性,隔离性和持久性。其中原子性,一致性,持久性更多是关注单个事务本身,比如,原子性要求事务中的操作要么都提交,要么都不提交;一致性要求事务的操作必须满足定义的约束,包括触发器,外键约束等;持久性则要求如果事务成功提交了,无论发生什么异常,包括进程crash,主机掉电等,都应该确保事务不会丢失。而隔离性,则关注的是多个事务之间的并发。
如果所有的事务都串行执行,相互不影响,不会有隔离的级别的问题。但是,串行无法充分发挥多核的优势,因此需要并发执行多个事务,并且"尽量"做到并发执行的事务与串行执行等价。为什么是"尽量"?是因为数据库中实际上不只有一种隔离级别,可串行化,所以才有必要讨论数据库中的隔离级别。比如拿MySQL举例,隔离级别包括,读未提交,读提交,可重复读,和串行化4种,其中可串行化是最严格的隔离级别,意味着事务之间产生冲突的概率最高。理论上,只有"可串行化"的事务序列才是"正确的",但是,由于数据库系统需要追求更好的性能,更高的系统吞吐,所以系统中会定义另外"比较弱"的隔离级别。每种"弱"的隔离级别定义,都会明确说明它会产生哪些"异常",如果用户能容忍这些"异常",很好,那么我们不用将数据库设置为最严的并发控制模式。所以,简单来说,通过隔离级别的设置,用户可以在"异常"和数据库性能之间做一个权衡。
数据库中异常
本文讨论的隔离级别主要源于论文A Critique of ANSI SQL Isolation Levels,论文中定义了一系列"异常",并且说明了不同的隔离级别分别解决了哪些"异常"。说明下文中,w[n]表示事务n写,r[n]表示事务n读,a[n]表示事务n-abort,c[n]表示事务n-commit。A0,P1,P2,P3,A4,A5等异常命名编号均来源于论文。
1.脏写
A0,dirty-write(WW),脏写
访问模式:w1[x], w2[x],c1,c2
两个事务先后写x,这种会导致w2事务覆盖w1的写。
2.脏读
P1,dirty-read(WR),脏读