MVCC(
Multi-Version Concurrency Control
),意为多版本并发控制。他是通过读取历史版本的数据,来降低并发事务冲突,从而提高并发性能的一种机制。
一、隐藏字段
MVCC + 锁机制(排他锁等)可以保证事务的隔离性。在 MySQL 中有 3个隐藏字段:
1.DB_TRX_ID: 记录最近修改事务的id
2.DB_ROLL_PIR: 回滚指针,指向该条记录的上一版本,配合undo log使用
3.DB_ROW_ID: 隐藏主键,如果数据库没有主键,MySQL会自动生成一个聚簇索引
undo log在insert、update、delete时产生回滚日志。
二、快照读和当前读
MySQL InnoDB 下的当前读
和快照读是指
1、快照读(普通读)
普通的 select 语句是快照读。执行方式是生成 readview(读视图),直接利用 MVCC 机制来读取,并不会对记录进行加锁。它是基于多版本并发控制即 MVCC机制,既然是多版本,那么快照读读到的数据不一定是当前最新的数据,有可能是之前历史版本的数据。
如下的操作是快照读:不加锁的 select 操作(事务级别不是串行化,串行化的是当前读)
2、当前读(锁定读)
这种方式读取的记录都是数据库中当前的最新版本,能读到所有已经提交的记录的最新值。它会对当前读取的数据进行加锁,防止其他事务修改数据,这种锁是一种悲观锁。
如下操作都是当前读:
(1)select … lock in share mode 当前读,加读锁 ,也叫共享锁
(2)select … for update 当前读,加写锁,又叫排他锁
(3)innoDB 里面 update (排他锁)、insert (排他锁)、delete (排他锁),都会自动给涉及的语句添加写锁。
(4)串行化事务的隔离级别
三、读视图
Read View 就是事务进行快照读操作的时候生产的读视图 ,在该事务执行的快照读的那一刻,会生成数据库系统当前的一个快照,记录并维护系统当前活跃事务的 ID (当每个事务开启时,都会被分配一个 ID , 这个 ID 是递增的,所以最新的事务,ID 值越大)。
在读已提交(RC)的隔离级别下,每一次执行快照读都会生成 Read View
在可重复读(RR,默认隔离级别)的隔离级别下,仅在第一次查询时生成 Read View
1.隐藏字段
Read View 有4个重要的字段:
(1)m_ids :指的是在创建 Read View 时,当前数据库中活跃事务的事务 id 列表,活跃事务指的就是,启动了但还没提交的事务。
(2)min_trx_id :指的是在创建 Read View 时,当前数据库中活跃事务中事务 id 最小的事务,也就是 m_ids 的最小值。
(3)max_trx_id :创建 Read View 时当前数据库中应该给下一个事务的 id 值,也就是全局事务中最大的事务 id 值 + 1。
(4)creator_trx_id :指的是创建该 Read View 的事务的事务 id。
2.可见性
一个事务去访问记录的时候,除了自己的更新记录总是可见之外,还有这几种情况:
(1)如果记录的 trx_id 值 < Read View 中的 min_trx_id 值,表示这个版本的记录是在创建 Read View 前已经提交的事务生成的,所以该版本的记录对当前事务可见。
(2)如果记录的 trx_id 值 >= Read View 中的 max_trx_id 值,表示这个版本的记录是在创建 Read View 后才启动的事务生成的,所以该版本的记录对当前事务不可见。
(3)如果记录的 trx_id 值在 Read View 的min_trx_id和max_trx_id之间,需要判断 trx_id 是否在 m_ids 列表中:
如果记录的 trx_id 在 m_ids 列表中,表示生成该版本记录的活跃事务依然活跃着(还没提交事务),所以该版本的记录对当前事务不可见。
如果记录的 trx_id 不在 m_ids 列表中,表示生成该版本记录的活跃事务已经被提交,所以该版本的记录对当前事务可见。
通俗的来说就是:版本记录对 在Read View创建之前的事务可见,在创建之前已经提交的事务可见。
四、整体流程
本文参考:https://blog.csdn.net/qingqingxiaocao1989/article/details/125094127、CSView