为什么有事务和隔离级别
事务是对一组操作原子性的保障,但正是由于事务,就会出现事务A和事务B数据之间的可见性问题(脏读,幻读,不可重复读)为了解决问题,才设置了隔离级别这种东西 。
隔离级别的一种实现思想就是mvcc,一行数据由于多个事务的修改可能会有多个版本。
隔离级别的实现
读未提交
每次读取的是数据最新版本。
串行化
事务之间不是并发执行的。
读取已提交
事务在每次执行语句时会创建新的快照,关闭之前的快照。
可重复读
事务开始执行,准确的说是事务第一次select时会创建快照,后续的读操作都是从快照里去读数据。
快照
是什么
是对数据库的临时拷贝,有个经常听到的说法是,可重复读是在事务开始时候的产生一个快照,但这个快照是什么意思,如果事务开始时,数据库是100G,那么我产生的快照也要100G吗,但显然不是的。
一行数据多个版本,如果每个事务知道自己要访问的版本,想象一个对象,每次事务创建一个对象,然后事务需要判断行数据的可见性时,调用这个对象就能知道结果,那我们就可以认为它是一个快照。
如何实现
我们知道,一行数据在数据库中会有多个版本,每个版本其实都记录了一个事务id(row trx_id),row trx_id和read-view就能实现一个快照的功能。
read-view
是什么
是 InnoDB 在实现 MVCC 时用到的一致性读视图,即 consistent read view,用于支持 RC(Read Committed,读提交)和 RR(Repeatable Read,可重复读)隔离级别的实现。
如何实现
为每个事务构造了一个数组,用来保存这个事务启动瞬间,当前正在“活跃”的所有事务 ID。
“活跃”指的就是,启动了但还没提交。数组里面事务 ID 的最小值记为低水位,当前系统里面已经创建过的事务 ID 的最大值加 1 记为高水位。
这个视图数组和高水位,就组成了当前事务的一致性视图(read-view)
InnoDB快照如何判断一行数据的可见和不可见的
这样,对于当前事务的启动瞬间来说,一个数据版本的 row trx_id,有以下几种可能:
如果落在绿色部分,表示这个版本是已提交的事务或者是当前事务自己生成的,这个数据是可见的;
如果落在红色部分,表示这个版本是由将来启动的事务生成的,是肯定不可见的;
如果落在黄色部分,那就包括两种情况
a. 若 row trx_id 在数组中,表示这个版本是由还没提交的事务生成的,不可见;
b. 若 row trx_id 不在数组中,表示这个版本是已经提交了的事务生成的,可见。
参考文献: