深度解析Mysql中MVCC的工作机制
MVCC,多版本并发控制
-
定义:维护一个数据的多个版本,使读写操作没有冲突,依赖于:隐藏字段,undo log日志,readView
-
MVCC会为每条版本记录保存三个隐藏字段
- DB_TRX_ID: 记录最近插入或修改该记录的事务ID
- DB_ROLL_PTR:回滚指针,指向这条记录的上个版本,配合undo log
- DB_ROW_ID:隐藏主键,如果没有指定主键,将会生成该隐藏主键
流程(重点):在修改数据前,innodb引擎会在undo log日志拷贝一份原记录,并将其DB_ROLL_PTR指向上一个版本,形成版本链。然后修改数据值,并把DB_TRX_ID改为当前执行的事务ID。
-
readView
-
定义:确定事务在快照读时能够看到数据库中的哪些数据版本。
-
区分:
当前读:读取的是记录的最新版本,对读取的记录加锁,保证读取时其他并发事务不能修改当前记录,解决幻读
快照读:select查询,不加锁,读取记录数据的可见版本(通过事务ID递增性判断是否可见)
- Read Commited:每次select都生成一个readView,读取可见记录中的最新版本,会造成不可重复读的问题
- Repetable Read:事务首次 select时生成 readView,后续复用该readView**
-
-
定义:确定事务在快照读时能够看到数据库中的哪些数据版本。
-
区分:
当前读:读取的是记录的最新版本,对读取的记录加锁,保证读取时其他并发事务不能修改当前记录,解决幻读
快照读:select查询,不加锁,读取记录数据的可见版本(通过事务ID递增性判断是否可见)
- Read Commited:每次select都生成一个readView,读取可见记录中的最新版本,会造成不可重复读的问题
- Repetable Read:事务首次 select时生成 readView,后续复用该readView
-
流程:基于快照读生成的readview,跟要查询的行数据的mvcc版本的DB_TRX_ID做比较,基于事务ID的递增性判断mvcc版本是否对当前readview可见,如果可见则返回当前mvcc版本的行数据,如果不可见,则通过mvcc的回滚指针回退到上一个版本。
-
判断MVCC版本是否对当前readView可见:mvcc版本的DB_TRX_ID字段 与 readView的字段比较,满足以下任意条件:
- DB_TRX_ID < min_trx_id(最小事务ID):该版本的事务比所有活跃事务(正在运行)更早创建且已提交,因此可见
- DB_TRX_ID = creator_trx_id(创建该readview的事务ID):当前事务自己生成的版本(即使未提交),对自己总是可见
- DB_TRX_ID < max_trx_id(预分配事务ID)&& DB_TRX_ID not in m_ids(活跃的事务ID列表中): 该版本的事务不在创建 read view 时的活跃事务列表中,说明已提交