MVCC
作者:互联网
什么是MVCC?
在InnoDB存储引擎中,MVCC 多版本并发控制(multi versioning), 是对一致性非锁定读的实现,MVCC 是一种用来解决读-写冲突的无锁并发控制,为事务分配单向增长的时间戳,为每个修改保存一个版本,版本与事务时间戳关联,读操作只能读到生成Read View之前已经完成的事务。在并发读写数据库时,可以做到在读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高了数据库并发读写的性能 同时还可以解决 脏读,幻读,不可重复读等事务隔离问题,但不能解决更新丢失问题
MVCC的实现原理
MVCC的实现依赖于3个隐藏字段,read view,undo log。在内部实现中innodb会把数据行中的隐藏字段DB_TRX_ID事务id与read view中的数据进行比较,判断数据的可见性,如果不可见则会通过数据行的DB_ROLL_PTR回滚指针,找到undo log中的历史版本。每个事务能看到的数据库版本可能是不一样的,用户只能读取到生成Read View之前已经提交的事务和该事务本身做的修改。
隐式字段
每行记录除了我们自定义的字段外,还有数据库隐式定义的DB_TRX_ID,DB_ROLL_PTR,DB_ROW_ID等字段
● DB_ROW_ID 6byte, 隐含的自增ID(隐藏主键),如果数据表没有主键,InnoDB会自动以DB_ROW_ID产生一个聚簇索引
● DB_TRX_ID 6byte, 最近修改(修改/插入)事务ID:记录创建这条记录/最后一次修改该记录的事务ID
● DB_ROLL_PTR 7byte, 回滚指针,指向这条记录的上一个版本(存储于rollback segment里)
● DELETED_BIT 1byte, 记录被更新或删除并不代表真的删除,而是删除flag变了
Read View (读视图)
Read View就是事务进行快照读操作的时候生产的读视图(Read View) 用于判断数据的可见性。里面保存了对当前事务不可见的其他事务。Read View里面主要包含了重要参数
- trx_list 生成read view时,还在活跃的事务id
- up_limit_id // trx_list当中的最小事务id
- low_limit_id // 生成read view时,数据库还未分配的下一个事务id
具体的比较算法时,把要读取的数据的DB_trx_id宇up_limit_id进行比较,
- 如果DB_Trx_id<up_limit_id,那么久证明,该数据的最新事务,时在生成read view事务前,因此对当前事务课件
- 如果DB_trx_id >= low_limit_id , 证明该数据时生成read view之后产生的,因此不可以见
- 如果DB_trx_id 在trx_list内,也是不可见的。表示生成read view时,该数据的事务还没有提交
快照读和锁定读
快照读
读取的是数据的一个快照,不一定是最新版本的一个数据
锁定读
读取的是数据的最新,锁定读会对读取到的记录进行加锁
- select ... lock in share mode
- select ... for update;
- insert 、update、delete操作
Undo log
为了回滚而记录的操作日志叫做undo log。比如:
- insert undo log :指在 insert 操作中产生的 undo log。因为 insert 操作的记录只对事务本身可见,对其他事务不可见,故该 undo log 可以在事务提交后直接删除。不需要进行 purge 操作
● update 的时候会把数据的旧值记录下来 - update undo log :update 或 delete 操作中产生的 undo log。该 undo log可能需要提供 MVCC 机制,因此不能在事务提交时就进行删除。提交时放入 undo log 链表,等待 purge线程 进行最后的删除
判断数据的可见性
在 InnoDB 存储引擎中,创建一个新事务后,执行每个 select 语句前,都会创建一个快照(Read View),快照中保存了当前数据库系统中正处于活跃(没有 commit)的事务的 ID 号。其实简单的说保存的是系统中当前不应该被本事务看到的其他事务 ID 列表(即 m_ids)。当用户在这个事务中要读取某个记录行的时候,InnoDB 会将该记录行的 DB_TRX_ID 与 Read View 中的一些变量及当前事务 ID 进行比较,判断是否满足可见性条件
RC 和 RR 隔离级别下 MVCC 的差异
在事务隔离级别 RC 和 RR (InnoDB 存储引擎的默认事务隔离级别)下,InnoDB 存储引擎使用 MVCC(非锁定一致性读),但它们生成 Read View 的时机却不同
● 在 RC 隔离级别下的 每次select 查询前都生成一个Read View (m_ids 列表)
● 在 RR 隔离级别下只在事务开始后 第一次select 数据前生成一个Read View(m_ids 列表)
MVCC 解决不可重复读问题
RR隔离级别下,第一次select 的时候生成Read View
MVCC➕Next-key-Lock 防止幻读
InnoDB存储引擎在 RR 级别下通过 MVCC和 Next-key Lock 来解决幻读问题:
1、执行普通 select,此时会以 MVCC 快照读的方式读取数据
在快照读的情况下,RR 隔离级别只会在事务开启后的第一次查询生成 Read View ,并使用至事务提交。所以在生成 Read View 之后其它事务所做的更新、插入记录版本对当前事务并不可见,实现了可重复读和防止快照读下的 “幻读”
2、执行 select...for update/lock in share mode、insert、update、delete 等当前读
在当前读下,读取的都是最新的数据,如果其它事务有插入新的记录,并且刚好在当前事务查询范围内,就会产生幻读!InnoDB 使用 Next-key Lockopen in new window 来防止这种情况。当执行当前读时,会锁定读取到的记录的同时,锁定它们的间隙,防止其它事务在查询范围内插入数据。只要我不让你插入,就不会发生幻读
标签:事务,Read,DB,MVCC,ID,View 来源: https://www.cnblogs.com/amberbar/p/16489042.html