本文摘录及参考自:
1. MySQL 四种事务隔离级的说明
2. 五分钟搞清楚MySQL事务隔离级别
3. 深入分析事务的隔离级别
4. 数据库隔离级别及其实现原理
5. 数据库的四个隔离级别
6. 数据库四大特性以及事务隔离级别
7. 数据库事务隔离级别-- 脏读、幻读、不可重复读(清晰解释)
8. MySQL事务隔离级别
数据库的事务隔离级别,其实是跟执行引擎相关的。以Mysql为例,Mysql支持的引擎就很多:MyISAM、InnoDB、MEMORY、BDB(BerkeleyDB)等等。但其中支持事务安全的只有两种引擎:InnoDB、BerkeleyDB。下面介绍支持事务安全的引擎所提供的事务隔离级别。
1. 事物隔离级别说明
读未提交:允许脏读,也就是可能读取到其他会话中未提交事物修改的数据
读已提交:只能读取到已经提交的数据。避免了脏读,这种隔离会出现“不可重复读”的现象,因为同一事务的其他实例在该实例处理其间可能会有新的commit,导致目标数据被修改,所以同一select可能返回不同结果。
可重复读:这是MySQL默认的隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行(目标数据行不会被修改)。不过,会出现“幻读”的现象。幻读是由insert引起的,简单来说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。
快照隔离: 为了解决幻读,数据库提供了快照隔离,也就是multi-version concurrency control (MVCC) 。事务在修改任何数据之前,先将原始数据行复制到tempdb,创建数据行的一个原始版本(Row Version)。此后该事物的操作不会看到版本高于Row Version的操作。快照隔离不会基础数据行或数据页上获取锁,这样可以执行其他事务,也不会被以前未完成的事务所阻止。修改数据的事务不会阻止读取数据的事务,读取数据的事务不会阻止写入数据的事务,就好像通常情况下在 SQL Server 中使用默认的 READ COMMITTED 隔离级别一样。
以图为例,就是事务12(txid=12)的所有快照读只会读取created by版本号小于等于自己的快照数据。但是仍然有可能出现写倾斜(看下文)。
可串行化:完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞
2. 异常现象说明
脏读:两个并发的事务 T1 和 T2,T1 修改了某一个数据项,然后 T2 读取该数据项并获取到了 T1 对其修改的结果,如果 T1 由于某些原因被回滚,则 T2 读到了一个不存在的结果.
不可重复读:两个并发的事务T1和T2,T1先读取了某个数据项,T2 再修改或者删除了该数据项并提交,然后 T1 再一次的读取这个数据项,它会发现该数据项的值发生了变 化或者该数据项已被删除.
丢失更新(Lost Update):两个并发的事务 T1 和 T2,T1 先读取了一个数据项,T2 修改了该数据项并提交,然后 T1 修改了这个数据项并提交.(快照隔离级别避免丢失更新的方法可以是:对于有更新或删除的事物,有一个try/catch,执行时比较版本,如果不一致则回滚整个事物)
幻读:T1对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,T2也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。
写倾斜(Write Skew):两个事务的读写集合互有交集,且不满足读写反依赖.例如,在避免脏读的事务系统中 存在两个并发事务 T1 和 T2,T1 和 T2 均未提交.事务 T1 读 X 写 Y,事务 T2 读 Y 写 X,因此 T1 和 T2 的读写集 合互有交集.在数据项X上,T1和T2的顺序为<T1, T2>;在数据项Y上,T1和T2的顺序为<T2, T1>.因此,事务 T1 和 T2 不满足读写反依赖。如下图
Alice和Bob都是基于快照读去做自己的逻辑操作,这就导致写倾斜(write skew )。
3. 事物隔离级别与异常现象之间的关系
下表展示了事务的隔离级别与异常现象之间的关系。总体而言,越强的事务一致性能够规避越多的异常现象。
脏读 | 不可重复读 | 丢失更新 | 幻读 | 写倾斜 | |
---|---|---|---|---|---|
读未提交 | 有 | 有 | 有 | 有 | 有 |
读已提交 | 无 | 有 | 有 | 有 | 有 |
可重复读 | 无 | 无 | 无 | 有 | 无 |
快照隔离 | 无 | 无 | 无 | 无 | 有 |
可串行化 | 无 | 无 | 无 | 无 | 无 |
4. 什么是MVCC
【高性能MySQL】中对 MVCC 的部分介绍
MySQL 的大多数事务型存储引擎实现的其实都不是简单的行级锁。基于提升并发性能的考虑, 它们一般都同时实现了多版本并发控制(MVCC)。不仅是 MySQL, 包括 Oracle,PostgreSQL 等其他数据库系统也都实现了 MVCC, 但各自的实现机制不尽相同, 因为 MVCC 没有一个统一的实现标准。
可以认为 MVCC 是行级锁的一个变种, 但是它在很多情况下避免了加锁操作, 因此开销更低。虽然实现机制有所不同, 但大都实现了非阻塞的读操作,写操作也只锁定必要的行。