详解SQL标准中的隔离级别定义

SQL标准中隔离级别的初衷

SQL标准,已被ANSIISO/IEC采用,定义了四种事务隔离级别。这些隔离级别在事务处理吞吐量上游不同程度的影响。
这些隔离级别根据并发执行事务时必须防止的现象定义。换言之,隔离级别定义的基础是可防止的现象(或者叫数据异常)。

数据异常/可防止的现象

早期的SQL标准只定义了如下三种常见数据异常:

  • 脏读(Dirty Reads)
    事务读取到另一个事务写入但至今未提交的数据。
  • 不可重复读(Nonrepeatable (fuzzy) reads)
    事务再次读取之前读过的数据,发现另一已提交事务修改或删除了这些数据(的部分或全部),对象是已有行
  • 幻读(Phantom reads)
    事务重新运行返回满足指定查询条件的结果集时,查到了其他已提交事务插入了满足查询条件的额外行,对象是原来不存在的新行

现今,随着数据库相关领域和应用程序的不断发展,NoSQL、NewSQL、分布式数据库的兴起,出现了很多新的数据异常,如丢失更新、写偏斜(Write Skew)、读偏斜、游标丢失更新等单机数据异常,和串行并发现象、交叉现象等分布式数据库异常,此处不加赘述,如有兴趣,请持续关注,后续会单独写文章讲解

解析

由上可见,SQL标准说的很清晰明确,修改(Update、Modify)、删除(Delete)针对的对象是已有行,是在该事务执行前表中已存在的行,重点强调已存在
而插入(Insert)针对的对象是额外的行,是在事务执行前表中不存在的行,事务执行过程中或执行完成后新增的行,重点强调新增

隔离级别的定义

SQL标准根据运行在特定隔离级别的事务被允许经历的现象定义了四个隔离级别。下表显示了这些级别。

隔离级别

脏读

不可重复读

幻读

读未提交

可能

可能

可能

读(已)提交

不可能

可能

可能

可重复读

不可能

不可能

可能

序列化(读)

不可能

不可能

不可能

Oracle支持的隔离级别

Oracle数据库支持读提交(默认)和序列化隔离级别。同时,Oracle还提供只读模式。

MySQL支持的隔离级别

MySQL数据库InnoDB存储引擎支持SQL:1992标准中的所有的四种隔离级别。InnoDB默认的隔离级别是可重复读(RR)。

多版本并发控制,目的是为了解决并发事务间的读写互斥,使用基于时间点的数据库快照技术和撤销日志(Undo Log)创建数据记录的多个版本来实现一致性非锁定读,而不是使用锁技术降低并发度和性能。

临键锁(Next-Key Lock) 索引记录锁Index Record Lock)和该索引记录前的 间隙锁Gap Lock)的合集,InnoDB在搜索和索引扫描时使用它来防止幻读行。

InnoDB的“可重复读”隔离级别相较于普通的“可重复读”比较特殊,额外增加了临键锁机制解决了锁定读下的幻读行的问题。但这只是间隙锁参数开关的影响,而非隔离级别上的功能。
在一致性非锁定读场景下,其“可重复读”隔离级别下MVCC的具体表现也与“读提交”不同,它执行一致性非锁定读读取到的快照是第一次执行该一致性读时的快照,即事务内的同一查询每次执行时读的是同一快照。而在“读提交”隔离级别下每次查询执行的是当前读,每次读取获取当前时间点数据库的最新快照,可能包含其他事务已提交的修改、删除。
简言之,“可重复读”隔离级别需要解决的是“不可重复读”问题,并不需要解决“幻读”问题,InnoDB可只通过MVCC解决一致性非锁定读下的不可重复读和幻读问题,需要(默认)启用间隙锁参数以实现临键锁机制来防止锁定读下“幻读”现象的发生。如果禁用该参数,仍然是“可重复读”隔离级别,只是会出现幻读。