MySQL系列之MVCC机制(四)

多版本并发控制(multi version concurrency control),MVCC 是一种并发控制的方法,是一个抽象概念,并非实现,一般在mysql中,实现对数据库的并发访问,不加锁就能让多个事务并发读写。从这里也可以体会到一种提高系统性能思路:通过版本号来减少锁的争用。

mysql中innodb的MVCC主要是为了提高并发读写性能,更好的解决读写冲突,当有冲突时,可以不加锁、非阻塞并发读。

MVCC 在 MySQL 中的实现是由 2 个隐式字段,undo log ,ReadView 等完成。

当前读

当前读就是读取的数据是最新版本,读取时保证其他并发事务不能修改当前数据,会对读取的数据加锁,因此当前读实际上是一种加锁的操作,是悲观锁的实现

当前读应用:共享锁、排它锁

快照读

快照读应用:不加锁的 select 操作(不加锁的非阻塞读)

快照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前读;

快照读目的是为提高并发性能,其实现是基于MVCC,可以认为 MVCC 是行锁的一个变种,在很多情况下,可以避免加锁操作,降低开销;

多版本表示快照读读到的不一定是数据的最新版本,有可能是历史版本。

数据库并发场景

数据库并发场景有三种,分别为:

  • 读读:不存在任何问题,也不需要并发控制
  • 读写:有线程安全问题,可能造成事务隔离性问题,可能遇到脏读,幻读,不可重复读
  • 写写:有线程安全问题,可能会存在更新丢失问题

MVCC + 悲观锁:MVCC解决读写冲突,悲观锁解决写写冲突

MVCC + 乐观锁:MVCC解决读写冲突,乐观锁解决写写冲突

undolog

一个数a,存的是1,将其update成2,undolog中记录的是1,它记录的是修改之前的数据

主要分为以下几种:

  • insert undo log:代表事务在 insert 时产生的 undo log,只在事务回滚时需要,并且在事务提交后可以被立即丢弃
  • update undo log:事务在进行 update 或 delete 时产生的 undo log ; 不仅在事务回滚时需要,在快照读时也需要;所以不能立即删除,只有在快照读或事务回滚不涉及该日志时,对应的日志才会被 purge线程统一清除
  • delete mark:记录打删除标记(逻辑删除)

purge

为了实现 InnoDB 的 MVCC 机制,更新或者删除操作都只是设置一下老记录的 deleted_bit ,并不真正将过时的记录删除。

为了节省磁盘空间,InnoDB 有专门的 purge 线程来清理 deleted_bit=true 的记录。为了不影响 MVCC 正常工作,purge 线程自己也维护了一个readview(相当于系统中最老活跃事务的 readview );如果某个记录的 deleted_bit=true,并且 DB_TRX_ID 相对于 purge 线程的 readview 可见,那么这条记录一定是可以被安全清除的。

版本链

不同事务或者相同事务对同一记录的修改,会使该记录的undo log成为一条版本链,链首就是最新的旧记录,链尾就是最早的旧记录(该undolog节点可能是会 purge 线程清除掉),主要用到两个必要的隐藏列db_trx_id和roll_pointer。

readview

事务一致性视图,就是事务进行快照读时生成的读视图,主要是用来做可见性判断的,当某个事务执行快照读时,对该记录创建一个ReadView读视图,用该readview作为条件,来判断当前事务能够看到哪个版本的数据。

readview包含四个比较重要内容:

  • m_ids:表示在生成readview时,当前系统中活跃的读写事务的事务id列表。
  • min_trx_id:表示在生成readview时,当前系统中活跃的读写事务最小的事务id,也就是m_ids的最小值。
  • max_trx_id:表示生成readview时,系统中应该分配给下一个事务的id值。max_trx_id并不是m_ids的最大值,事务id时递增分配的,若现在有id为1,2,3的事务,之后id为3的事务提交了,一个新的读事务在生成readview时,m_ids就包含了1和2,min_trx_id的值就是1,max_trx_id的值就是4。
  • creator_trx_id:表示生成该readview的事务的事务id。

根据readview,在访问某条记录时,只需按下边的步骤判断记录的某个版本是否可见:

  1. 如果被访问版本的trx_id值==creator_trx_id值,表示当前事务在访问它自己修改过的记录,所以该版本可以被当前事务访问。
  2. 如果被访问版本的trx_id值<min_trx_id值,表明生成该版本的事务在当前事务生成readview前已经提交,所以该版本可以被当前事务访问。
  3. 如果被访问版本的trx_id值>max_trx_id值,表明生成该版本的事务在当前事务生成readview后才开启,所以该版本不可以被当前事务访问。

具体流程

MVCC为事务分配单向增长的时间戳,为每个修改保存一个版本,版本与事务时间戳关联,读操作只读该事务开始前的数据库的快照。 所以 MVCC 可以为数据库解决以下问题:

  • 并发读写时,在读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高并发读写性能
  • 解决脏读,不可重复读,幻读等事务隔离问题,但不能解决更新丢失问题

MVCC发生在事务隔离级别的READ COMMITTED(提交读)REPEATABLE READ(可重复读)已提交读和可重复读的区别就在于它们生成ReadView的时机不同。

READ UNCOMMITTED 总是读取最新的数据行,而不是符合当前事务版本的数据行,所以不存在版本问题。

SERIALIZABLE则会对所有读取的行都加锁。

已提交读隔离级别的事务在每次查询的开始都会生成一个ReadView。

可重复读隔离级别的事务在第一次读的时候生成一个ReadView,之后的读都复用之前的ReadView。

mysql在每一行记录的后面用两个隐藏列,记录创建版本号和删除版本号,而每一个事务在启动的时候,都有一个唯一的递增版本号。

两个必要的隐藏列:

db_trx_id: 6 byte,创建/最后一次修改该记录的事务 ID

roll_pointer: 存了一个指向这条聚簇索引记录的上一个版本位置的指针,通过它来获得上一个版本的记录信息。每次对哪条聚族索引记录有修改的时候,都会把老版本写入undolog中(插入操作的undolog没有这个属性,因为它没有老版本)

思路:开始事务时创建readview,readview维护当前活动的事务id(未提交的事务id),排序生成一个数组访问数据,获取数据中的事务id (获取的是事务id最大的记录),通过上述readview对比方式进行比对,以此判断该版本记录是否可以被访问。再获取rollpointer,取上一版本重新对比。

插入操作时: 记录的创建版本号就是事务版本号。

更新操作时:采用的是先标记旧的那行记录为已删除,并且删除版本号是事务版本号,然后插入一行新的记录的方式。

比如,事务Id=2把name字段更新:update table set name= 'new_value' where id=1;

删除操作时:就把事务版本号作为删除版本号。对于删除的情况可以认为是update的特殊情况,会将版本链上最新的数据复制一份,然后将trx_id修改成删除操作的trx_id,同时在该条记录的头信息 (record header)里的 (deleted flag)标记位写上true,来表示当前记录已经被删除,在查询时按照查询流程,查到对应的记录如果delete flag标记位为true,意味着记录已被删除,则不返回数据

查询操作时

要符合以下两个条件的记录才能被事务查询出来:

  • InnoDB只查找版本早于当前事务版本的数据行(行的系统版本号小于或等于事务的系统版本号),这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改过的。
  • 行的删除版本要么未定义,要么大于当前事务版本号。这可以确保事务读取到的行,在事务开始之前未被删除。

这样就保证了各个事务互不影响。

read committed实现方式

每次读取数据前都生成一个readview

repeatable read实现方式

第一次读取数据时生成一个readview

RR级别下防止幻读

快照读:使用MVCC防止幻读

当前读:使用间隙锁防止幻读

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
MySQLMVCC(Multi-Version Concurrency Control)机制是一种并发控制机制,用于处理并发事务的读写冲突。它通过为每个事务创建一个独立的版本,并使用这些版本来提供对数据的一致性读取,从而实现并发控制。 MVCC机制MySQL中的实现主要依赖于以下两个重要的组件: 1. Undo日志:MySQL使用undo日志记录数据修改操作的旧值。当一个事务开始时,MySQL会将当前数据行的快照复制到undo日志中。如果其他事务需要读取该数据行,它将读取这个快照而不受正在进行的事务的影响。 2. Read View:Read View是一个事务的快照视图,用于确定哪些数据行是对当前事务可见的。每个事务在开始时都会创建一个Read View。Read View包含一个活动事务列表和一个已提交事务列表。活动事务列表包含当前正在运行的活动事务,已提交事务列表包含已经提交的事务。当一个事务需要读取数据时,它会根据Read View确定哪些数据行是可见的。 基于这两个组件,MVCC机制提供了以下几个特点: 1. 高并发性:MVCC机制允许多个事务并发地读取和修改数据,因为它们之间不会产生读写冲突。 2. 一致性读取:MVCC机制确保事务只能读取已经提交的数据,避免了脏读和不可重复读的问题。 3. 无锁读取:MVCC机制的读取操作不会阻塞写入操作。读取操作只需要根据Read View判断数据是否可见。 需要注意的是,MVCC机制只适用于InnoDB存储引擎,而不适用于其他存储引擎,如MyISAM。另外,MVCC机制在一些特殊情况下可能会导致存储空间的增加,因为每个事务都会创建一个版本。因此,在设计数据库时需要考虑这些因素。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值