MySQL系列文章
事务特性
首先mysql事务的四大特性分别为
- 原子性
- 一致性
- 隔离性
- 持久性
其中原子性、一致性、持久性通过依赖MySQL的日志系统做保证,概念模糊的同学可以过一下往期整理的日志系统文章【浅谈日志系统】。而隔离性则是通过MVCC特性与readview实现。
redolog与undolog在【浅谈日志系统】中都有介绍,遇到这个问题的时候可以把相关的点串起来回答,本篇主要说一下隔离性的实现。
MVCC
基本概念
- 当前读:读取当前记录的最新版本,对数据加锁。sql中如select ... lock in share mode(共享锁),select ... for update、update、insert、delete(排他锁)都是一种当前读。
- 快照读:读取的是数据版本链上的某一个版本,有可能是历史数据,不加锁,属于非阻塞读。常见的select * from语句就属于快照读。
- mvcc:全称为多版本并发控制,可以通俗理解为数据并不是只存一份,而是对与不同的事务存储了一整数据变动版本链条。用于实现不同事务之间读写操作不用通过加锁来避免冲突。
实现原理
隐藏字段
- 其实在数据表中的每行数据除了使用者自己创建出的字段以外,InnoDB还为每一行存储了两个关键隐藏字段。
- DB_TRX_ID,最近修改事务ID,记录这条记录的最后一次修改该记录的事务id
- DB_ROLL_PTR,回滚指针,指向这条记录的上一个版本,用于配合 undolog,指向上一个版本。
undolog
- 回滚日志,所有的insert、update、delete语句都会产生用于于数据回滚的日志。
- undolog分为
- insert undolog,insert语句产生的的日志,事务提交后
- update undolog,delete和update语句产生的日志,事务提交后放到history list中,用于保证快照读,等待purge线程进行最终删除。
- 不同事务或相同事务对同一条记录进行修改,会导致该记录的undo log生成一条记录版本链表,链表的头部是最新的旧记录,链表尾部是最早的旧记录。
read view
- 读视图,与create view的视图概念截然不同。ReadView(读视图)是快照读 SQL执行时MVCC提取数据的依据,记录并维护系统当前活跃的事务(未提交的)id
- 包含四个核心字段
- m_ids,当前活跃的事务 ID 集合
- min_trx_id,最小活跃事务 ID
- max_trx_id,预分配事务 ID ,当前最大事务 ID+1 (因为事务 ID 是自增的)
- creator_trx_id,ReadView 创建者的事务 ID
- readview将当前系统活跃的读写事务,把它们的事务id放到一个m_ids列表中
- 被访问版本的事务id小于m_ids的最小事务id,表示生成该版本的事务在生成readview前已经提交
- 如果被访问版本的 trx_id 属性值大于 m_ids 列表中最大的事务id,表明生成该版本的事务在生成 ReadView 后才生成,所以该版本不可以被当前事务访问。
- 如果被访问版本的 trx_id 属性值在 m_ids 列表中最大的事务id和最小事务id之间,那就需要判断一下 trx_id 属性值是不是在 m_ids 列表中,如果在,说明创建 ReadView 时生成该版本的事务还是活跃的,该版本不可以被访问;如果不在,说明创建 ReadView 时生成该版本的事务已经被提交,该版本可以被访问