隔离性
隔离级别
- 读未提交(read uncommitted);
一个事务还未提交时,它的变更就能被别的事务看到。(脏读问题) - 读提交(read committed);
一个事务提交之后,它做的变更才会被其他事务看到。(不可重复读、幻读问题) - 可重复读(repeatable read);
一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。 - 串行化(serializable)。
对于同一行记录,写会加写锁,读会加读锁。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。
不同隔离级别,在一些场景看到的查询结果是不同的,在实现上,是通过创建一个视图,访问的时候以这个视图为准:
- 可重复读,这个视图是在事务启动时创建的,整个事务存在期间都用这个视图;
- 读提交,这个视图是在每个SQL语句开始执行的时候创建的;
- 读未提交,直接返回记录上最新的值;
- 串行化,加锁避免并行访问。
MVCC
- read view
实现mvcc用到的一致性视图,即 consistent read view,用于支持RC和RR隔离级别的实现。
RC级别下,每一个SQL语句创建一个read view;RR隔离级别下,在事务一开始创建一个read view并一直使用。
- 事务id
InnoDB每个事务都有一个唯一的事务id,叫做transaction id,是在事务开始时向事务系统申请的,按照申请顺序严格递增。
每行数据都有一个隐藏字段row_trx_id,这个字段的值就是transaction id。
- undo log
每条记录在更新的的同时会记录一条回滚操作(undo log),记录上最新的值,可以通过回滚操作,得到前一个状态的值。同一条记录在系统可以存在多个版本,这就是数据库的多版本并发控制(MVCC)。
回滚日志会在不需要的时候删除:系统里面没有比这个回滚日志更早的read-view的时候。
- 可重复读实现
- 事务数组:InnoDB为每个事务构造了一个数组,用来保存这个事务启动的时候,当前正在活跃(启动但还未提交)的所有事务id;
- 低水位:数组里面事务id的最小值;
- 高水位:当前系统里面已经创建过的事务id最大值+1;
- 一致性视图:由事务数组和高水位组成。
数据版本的可见性,基于数据的row_trx_id和一致性视图对比的结果。对于当前事务启动瞬间来说,一个数据版本的row_trx_id可能有几种情况:
- 绿色部分:这个版本是已提交的事务或者当前事务自己生成的,这个数据是可见的;
- 红色部分:这个版本的数据是由将来启动的事务生成的,是不可见的;
-
黄色部分:a.如果如果row_trx_id在数组中,表示这个版本是由还没提交的事务生成的,不可见;b.如果row_trx_id不在数组中,表示这个版本是已经提交了的事务生成的,可见。
总结来说:
- 版本未提交,不可见;
- 版本已提交,但是实在视图创建后提交的,不可见;
- 版本已提交,而且实是在视图创建前提交的,可见。
- 一致性读和当前读
- 一致性读:普通查询都是一致性读,具有可重读的特点;
- 当前读:更新数据都是先读后写的,而这个读,只能读当前的值,称为“当前读”。
网友评论