likes
comments
collection
share

多版本并发控制MVCC(精简版,长话短说)

作者站长头像
站长
· 阅读数 81

1.当前读与快照读

当前读,它读取的数据库记录,都是当前最新版本,会对当前读取的数据进行加锁,防止其他事务修改数据。是悲观锁的一种操作。

如下操作都是当前读:

  • select lock in share mode (共享锁)
  • select for update (排他锁)
  • update (排他锁)
  • insert (排他锁)
  • delete (排他锁)
  • 串行化事务隔离级别

快照读,的实现是基于多版本并发控制,即MVCC,既然是多版本,那么快照读读到的数据不一定是当前最新的数据,有可能是之前历史版本的数据。

如下操作是快照读:

  • 不加锁的select操作(注:事务级别不是串行化)

2.Read View

Read View用于支持RC(Read Committed,读提交)和RR(Repeatable Read,可重复读)隔离级别实现

  • RC隔离级别下,是每个快照读都会生成并获取最新Read View
  • 而在RR隔离级别下,则是同一个事务中第一个快照读才会创建Read View, 之后的快照读获取的都是同一个Read View,之后的查询就不会重复生成了,所以一个事务的查询结果每次都是一样的

事务进行快照读操作的时候生产的读视图(Read View),在该事务执行的快照读的那一刻,会生成数据库系统当前的一个快照

记录并维护系统当前活跃事务的ID(没有commit,当每个事务开启时,都会被分配一个ID, 这个ID是递增的,所以越新的事务,ID值越大),是系统中当前不应该被本事务看到的其他事务id列表

Read View主要是用来做可见性判断的, 即当我们某个事务执行快照读的时候,对该记录创建一个Read View读视图,把它比作条件用来判断当前事务能够看到哪个版本的数据,既可能是当前最新的数据,也有可能是该行记录的undo log里面的某个版本的数据。

Read View几个属性

  • trx_ids: 当前系统活跃(未提交)事务版本号集合。
  • low_limit_id: 创建当前read view 时“当前系统最大事务版本号+1”。
  • up_limit_id: 创建当前read view 时“系统正处于活跃事务最小版本号
  • creator_trx_id: 创建当前read view的事务版本号;

以上属性非常重要,会用来判断行数据对于当前事务是否可见。

3. 数据行的隐藏字段

我们数据库中的每行数据,除了我们肉眼看见的数据,还有几个隐藏字段,得开天眼才能看到。分别是db_trx_iddb_roll_pointerdb_row_id

  • db_trx_id

    6byte,最近修改(修改/插入)事务ID:记录创建这条记录/最后一次修改该记录的事务ID

  • db_roll_pointer(版本链关键)

    7byte,回滚指针,指向这条记录上一个版本(存储于rollback segment里)

  • db_row_id

    6byte,隐含的自增ID(隐藏主键),如果数据表没有主键,InnoDB会自动以db_row_id产生一个聚簇索引

  • 实际还有一个删除flag隐藏字段, 记录被更新删除并不代表真的删除,而是删除flag变了,只有在快速读或事务回滚不涉及该日志时,对应的日志才会被purge线程统一清除

多版本并发控制MVCC(精简版,长话短说)

这些数据会在undolog(日志文件)里面通过db_roll_pointer来形成一个链表,这个链表也可成为版本链。

多版本并发控制MVCC(精简版,长话短说)

4. 数据行在事务中可见性判断(Read View可见性)

  • db_trx_id < up_limit_id || db_trx_id == creator_trx_id(显示)

    如果数据事务ID小于read view中的最小活跃事务ID,则可以肯定该数据是在当前事务启之前就已经存在了的,所以可以显示

    或者数据的事务ID等于creator_trx_id ,那么说明这个数据就是当前事务自己生成的,自己生成的数据自己当然能看见,所以这种情况下此数据也是可以显示的。

  • db_trx_id >= low_limit_id(不显示)

    如果数据事务ID大于read view 中的当前系统的最大事务ID,则说明该数据是在当前read view 创建之后才产生的,所以数据不显示。如果小于则进入下一个判断

  • db_trx_id是否在活跃事务(trx_ids)中

    • 不存在:则说明read view产生的时候事务已经commit了,这种情况数据则可以显示
    • 已存在:则代表我Read View生成时刻,你这个事务还在活跃,还没有Commit,你修改的数据,我当前事务也是看不见的。

以上便是MVCC的精简版知识。

转载自:https://juejin.cn/post/7102431719441055775
评论
请登录