隔离级别
事务隔离级别
在前面章节中,我们介绍了事务的
- 脏读:一个客户端读取到另一个客户端尚未提交的写入。读已提交或更强的隔离级别可以防止脏读。
- 脏写:一个客户端覆盖写入了另一个客户端尚未提交的写入。几乎所有的事务实现都可以防止脏写。
- 读取偏差(不可重复读
) :在同一个事务中,客户端在不同的时间点会看见数据库的不同状态。譬如B 事务读到了A 事务已经提交的数据,即B 事务在A 事务提交之前和提交之后读取到的数据内容不一致(AB 事务操作的是同一条数据) ;快照隔离经常用于解决这个问题,它允许事务从一个特定时间点的一致性快照中读取数据。快照隔离通常使用多版本并发控制(MVCC)来实现。 - 更新丢失:两个客户端同时执行读取
- 修改- 写入序列。其中一个写操作,在没有合并另一个写入变更情况下,直接覆盖了另一个写操作的结果。所以导致数据丢失。快照隔离的一些实现可以自动防止这种异常,而另一些实现则需要手动锁定(SELECT FOR UPDATE) 。 - 写偏差:一个事务读取一些东西,根据它所看到的值作出决定,并将决定写入数据库。但是,写入的时候,决定的前提不再是真实的。只有可序列化的隔离才能防止这种异常。
- 幻读:事务读取符合某些搜索条件的对象。另一个客户端进行写入,影响搜索结果。譬如
B 事务读到了A 事务已经提交的数据,即A 事务执行插入操作,B 事务在A 事务前后读到的数据数量不一致。快照隔离可以防止直接的幻像读取,但是写入歪斜环境中的幻影需要特殊处理,例如索引范围锁定。
为了解决这些问题,就有了隔离级别的概念,
- Read Uncommitted(读未提交)
: 一个事务还没提交时,它做的变更就能被别的事务看到,读取尚未提交的数据,哪个问题都不能解决; - Read Committed(读已提交
) :一个事务提交之后,它做的变更才会被其他事务看到,读取已经提交的数据,可以解决脏读;这也是Oracle 默认级别。 - Repeatable Read(可重复读
) :一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的,可以解决脏读和不可重复读;这是MySQL 的默认级别 - Serializable(串行化
) :顾名思义是对于同一行记录, “写”会加“写锁”, “读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。可以解决脏读、不可重复读和虚读—相当于锁表。
其中,这些不同的隔离级别可以分为弱隔离级别与可序列化两大类,弱隔离级别可以防止这些异常情况,但是让应用程序开发人员手动处理其他应用程序(例如,使用显式锁定
事务隔离的实现方案
事务隔离级别有两种常见的实现方案,即锁实现和
隔离级别 | 脏读脏写 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交 | 可能 | 可能 | 可能 |
读已提交 | 不可能 | 可能 | 可能 |
可重复读 | 不可能 | 不可能 | 可能 |
可序列化 | 不可能 | 不可能 | 不可能 |
而基于
隔离级别 | 脏读脏写 | 不可重复读 | 幻读 | 写偏序 |
---|---|---|---|---|
读未提交 | 无需实现 | 无需实现 | 无需实现 | 无需实现 |
读已提交 | 不可能 | 可能 | 可能 | 可能 |
可重复读 | 不可能 | 不可能 | 不可能 | 可能 |
可序列化 | 不可能 | 不可能 | 不可能 | 不可能 |
通过