带你了解MVCC多版本并发控制,以及RC、RR、事务的原子性是如何实现的

MVCC简介       

 MVCC及多版本并发控制机制,在mysql的Innodb中主要是为了提高数据库并发性能,做到即使有读写冲突时,也能够以非阻塞的方式运行。

        MVCC的具体实现是由行记录的隐藏字段、undo log日志以及Read View根据可见性算法共同完成的。

行记录的隐式字段

在mysql数据库表的每行记录中,除了我们自己定义的字段外,还有几个隐藏字段:

  • db_trx_id
    • 6 byte
    • 最近插入/修改的事务ID:记录创建这条记录/最后一次修改该记录的事务ID
  • db_roll_ptr
    • 7 byte
    • 回滚指针,指向这条记录的上一个版本
  • db_row_id
    • 6 byte
    • 隐含的自增ID(隐藏主键)

undo 日志版本链

undo log主要分为两种:

1、insert undo log

  • 代表事务在insert时产生的undo log;
  • 只在事务回滚时需要,并且在事务提交后可以被立即丢弃;

2 、update undo log

  • 事务在进行update或delete时产生的undo log
  • 不仅在事务回滚时需要,在快照读时也需要,所以不能随便删除
  • 只有在快照读或事务回滚不涉及该日志时,对应的日志才会被purge线程统一清理

带你了解MVCC多版本并发控制,以及RC、RR、事务的原子性是如何实现的_第1张图片

ReadView

Read View是事务进行快照读操作的时候产生的读视图,在该事务执行的快照读的那一刻,会生成数据库系统当前的一个快照,记录并维护系统当前活跃事务的ID。

它主要由四部分组成:

  • trx_ids
    • 一个数值列表;
    • 用于维护Read View生成时刻系统正在活跃(begin但还未commit)的事务ID列表;
  • low_limit_id
    • 是trx_ids列表中事务ID最小的ID
  • up_limit_id
    • 是ReadView生成时刻系统尚未分配的下一个事务ID,是所有事务ID中最大值+1;
  • creator_trx_id
    • 创建该ReadView的事务的事务ID

带你了解MVCC多版本并发控制,以及RC、RR、事务的原子性是如何实现的_第2张图片

MVCC是如何通过undo log和ReadView实现隔离性的呢?

        当事务启动时,会读取一个数据版本的事务ID(trx_id),将当前数据版本的事务ID(undo log版本链中最新的)和creator_trx_id做比较,若相等,则代表查询操作是在当前数据版本的一个事务中进行的(在访问我自己修改的事务),则这个数据版本是可见的;若数据版本的事务ID < low_trx_id,则证明此数据版本是已提交过的数据(事务的数据版本中的事务ID是随着事务中修改操作递增的);若数据版本的事务ID > max_trx_id,则证明当前的数据版本是由将来的事务生成的,所以对于当前事务而言是看不到的,因此不可见;若落在中间的红色区域呢,分两种情况,1、当前数据版本的事务ID存在于trx_ids列表中,则证明该数据版本的事务还未提交,因此也不可见;2、当前数据版本的事务ID不存在于trx_ids中,则证明该数据版本的事务已提交,因此应该可见。

        如果undo log版本链中的事务ID和ReadView快照中经过上述过程匹配时,出现了不可见的情况,那么就根据版本链的db_roll_ptr回滚指针去之前的数据版本重新进行匹配。

RC提交读级别

在RC事务隔离级别下,事务里每次执行查询操作时,ReadView都会按照数据库当前状态重新生成ReadView,也就是每次查询都是跟数据库里当前所有事务提交状态来比对数据是否可见,以至于每次都能查到已提交的最新数据效果了。

RR可重复读级别

事务里每次执行查询操作ReadView都是使用第一次查询时生成的ReadView,也就是都以第一次查询时数据库中事务的提交状态来比对数据是否可见,以至于每次查询可以实现可重复读的效果。另外,若在该事务隔离级别下修改数据,事务会重新获取最新的ReadView,并不会出现拿旧数据去做修改的情况,也不必加锁就可以实现对数据的并发访问和修改。

事务的原子性

        事务中的一系列操作,要么都执行,要么都不执行,mysql使用undo log对该特性进行实现,如果事务中出现错误或要回滚,就会通过undo log进行数据回滚

Undo Log是MySQL中的一种日志记录方式,它记录了事务执行前的数据状态,用于在事务回滚时恢复数据。下面将详细介绍MySQL如何通过Undo Log实现事务的原子性。

  1. 事务的开始: 当一个事务开始时,MySQL会为该事务分配一个唯一的事务ID(Transaction ID)。事务ID在数据库中是递增的,每个事务都有一个唯一的ID标识。

  2. 数据的修改: 在事务执行期间,如果对数据库中的数据进行了修改(插入、更新、删除等操作),MySQL会将这些修改操作记录到Undo Log中。具体的记录方式是将修改前的数据(旧值)存储在Undo Log中,以便在事务回滚时可以恢复数据。

  3. 事务的提交: 当一个事务执行完成后,如果没有发生错误,事务将被提交。在提交之前,MySQL会将事务ID和Undo Log中的记录进行关联,以表示这些操作属于同一个事务。同时,MySQL会将这些修改操作应用到数据库中的数据文件中,从而实现数据的持久化。

  4. 事务的回滚: 如果一个事务在执行过程中发生了错误,或者用户显式地执行了回滚操作,事务将被回滚。在回滚时,MySQL会根据事务ID查找Undo Log中的记录,并将这些记录中的旧值恢复到数据库中,从而撤销事务执行过程中的修改操作。

        通过Undo Log机制,MySQL实现了事务的原子性。当一个事务执行成功时,所有的修改操作都会被持久化到数据库中,数据的一致性得到了保证。而当一个事务执行失败或者回滚时,Undo Log中的记录可以被用来恢复数据,从而保证了事务的原子性。

        需要注意的是,Undo Log是MySQL中的一种临时存储机制,它存储在内存中或者磁盘的临时文件中。当事务提交或者回滚后,Undo Log中的记录会被清除,释放空间。

总结

        MVCC是事务的隔离性的解决方法,事务的四大原则,ACID(原子性、一致性、隔离性、持久性),了解其他原则也很重要,感兴趣的朋友可以去了解一下事务其他特性的实现原理。

你可能感兴趣的:(数据库)