事务的隔离级别
可重复读:查询只承认在事务启动之前已经提交的数据
读提交:查询只承认在语句启动前已经提交的数据
当前读:总是读取已经提交完成的最新版本
在Mysql中有两个视图的概念:
1、一个是view,一个用查询语句定义的虚拟表,在调用的时候执行查询语句并返回结果
2、另外是InnoDB为了实现MVCC时用到的一致性视图,用于支持RC-读提交、RR-可重复读隔离级别的实现
快照在MVCC的工作方式简述:
可重复读隔离级别,事务在启动的时候基于整个库“拍”了个快照;实际上他的快照操作并不是对数据的复制,不然就不会快速的启动一个事务,实际上是基于事务的ID来实现的
事务启动会向InnoDB事务系统申请一个事务ID,每一行数据都会有多个版本,即数据的每次更新都会向系统申请一个新的事务ID(事务ID的生成方式上一篇《自增id用完怎么处理》说过);旧的版本要保留且可以通过新的版本中的数据(undo log)拿到,在实现上InnoDB为每个事务构造了一个数组,用来保存事务启动瞬间还“活跃”的所有事务ID,活跃指启动还没有提交。数组中事务ID最小的为“低水位”,最大的事务ID+1为高水位,这个视图数组和高水位组成了一致性视图(read-view);数据的可见行规则就是根据这个视图对比得到的结果。
视图数组把所有row trx_id分为:已提交事务、未提交事务集合(当前事务)、未开始事务;
一个数据版本的row trx_id落在已提交集合则数据是可见的,落在未开始集合数据不可见,落在为提交事务集合则分为两种情况(落在集合并不一定表示一定在集合只能说明比高水位的row trx_id小):在数组中表示该版本由还未提交的事务生成 不可见,不在集合中表示由已提交的事务生成 可见(这里其实搞的不是很明白,,,记录下来)。所以InnoDB利用所有数据多版本的特性,秒级创建了快照
这种说法更浅显一点:一个数据版本,对于数据视图来说除了自己的更新可见以外有以下三种情况:
1、版本未提交 不可见
2、版本已提交,在视图数组创建之后提交 不可见
3、版本已提交,在视图数组创建之前提交 可见
注:更新数据时有一条逻辑--更新数据时总是先读后写,而这个读指的是 当前读;必须要读取最新版本的数据,且必须加锁
其实这就和可重复读隔离级别就有点相悖了;那事务的可重复读的隔离级别是怎么实现的?
即:可重复读的核心是一致性读,事务在更新数据时只能用当前读,如果当前记录的行锁被其他事务占用,那就需要进入所等待
另--读提交和可重复读的区别:
1、可重复读隔离级别下,只需要事务开始时创建一致性视图,后续事务里的其他查询操作都共用这一个视图
2、读提交隔离级别下,每次执行语句前都会创建一个新的视图
小小结:
开始也做了一个小结,这里提一个小点:表结构不支持“可重复读”的原因是,表结构没有对应的行数据,也没有row trx_id 所以只有遵循当前读的逻辑
参考林晓斌《Mysql45讲》