MVCC多版本并发控制在mysql的应用

MVCC多版本并发控制

MVCC多版本并发控制一种并发控制的方法,一般用在数据库管理系统,实现对数据库的并发访问,在编程语言中实现事务内存。

  • 对于mysql innodb的应用主要是为了提高并发性能,用更好的方式处理读写冲突,做到即便有读写冲突,也可以做到不加锁的非阻塞并发读。

mvcc解决的问题

  • 对于数据库而言,存在三种并发场景:
  1. 读读:不存在问题。
  2. 读写:有线程安全问题,可能造成事务隔离性问题。
  3. 写写:有线程安全问题,可能存在更新丢失问题。

因为mvcc是一种用来解决读写冲突的无锁并发控制,也就是为事务分配单项增长的时间戳,为每个修改保存一个版本,版本与事务时间戳关联,所以可以解决:

  1. 并发读写时,可以做到读写不阻塞,提供并发读写性能。
  2. 解决幻读、脏读、不可重复读等事务隔离问题,但是不能解决更新丢失问题。

引入

  • 因为对于不同版本的事务隔离级别,读取到的数据是一不一样的,主要在于当前执行sql的时候是当前读还是快照读。

当前读

读取最新的数据,比如加锁的select。
读取的时候保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。

select * from xx_table lock in share mode 

select * from xx_table for update;

insert into xx_table;

快照读

读取的是历史版本的数据,即快照生成的那一刻的数据。

  • 快照读产生的前提:基于提供并发性能的考虑,快照读的实现基于MVCC。
  • 快照读的前提:隔离级别不是串行化,串行化下:快照读会退化为当前读。
  • 像不加锁的select就是快照读。
select * from table where ...

RC、RR级别下Innodb快照读有什么不同

  • RC下,一个事务中的每次select都会产生一个read view。
  • RR下,一个事务中,只在第一次select中产生一次read view。

快照读、MVCC关系

  • mvcc指的是一个数据库的多个版本,使的读写操作没有冲突。
  • 快照读是mysql为实现MVCC的一个非阻塞读功能。

MVCC实现原理

mvcc在mysql 的实现由三个组件实现:

  1. 三个隐式字段。
  2. undolog。
  3. read view。

隐藏字段

  • 除了每行记录我们自定义的字段外,还有数据库隐式定义的三个字段。
  1. DB_TRX_ID:6字节,当前事务的ID,绑定在每一个行上面,每次都是递增的。
  2. DB_ROLL_PTR:7字节,回滚指针,指向这条记录的上一个版本,配合undolog,指向上一个旧版本。
  3. DB_ROW_ID:6字节,隐藏主键,因为innodb是一个聚簇索引,当进行数据插入的时候,必须跟某个索引列绑定在一起,如果有主键则用主键,没有的话,看下是否有唯一键,如果有则用,否则使用6字节的rowID。
    在这里插入图片描述
    比如上图
  • DB_ROW_ID:是数据库默认为改行记录生成的唯一隐式主键。
  • DB_TRX_ID:当前操作该记录的事务ID。
  • DB_ROLL_PTR:回滚指针。

注意:刚插入数据的时候,DB_ROLL_PTR是空的。

undo log

称为回滚日志,表示在insert/delete/update操作时删除的方便回滚的日志。

  • 在insert的时候,产生的日志只在事务回滚的时候用,并且在事务提交后可以被立即丢弃,多个版本的历史数据是不会持久保留的,当持久化到磁盘之后,会删除对应的数据。
  • 在update/delete的时候,产生的日志不仅在事务回滚,而且在快照读的时候也需要,所以不能随意删除,只有在快照读/事务回滚不涉及该日志的时候,对应的日志才会被purge线程统一清楚。(因为对于更新/删除,只是设置一下老记录的deleted_bit,并不是真正将过时记录删除,为了节省磁盘空间,innodb有专门的purge现场来清除deleted_bit=true的记录,如果某个记录的delete_bit=true,而且DB_TRX_ID和purge线程的read view可见,那么这条记录一定是可以被清除的)。
undolog记录链生成流程
  1. 先加排它锁
  2. 拷贝数据到undolog
  3. 修改行数据和隐藏事务id
  4. 回滚指针指向undolog副本记录
  5. 提交事务释放锁

read view

是事务进行快照读操作时蔡山的读事图,在该事物执行快照的那一刻,会生成一个数据库系统当前的快照,记录并维护当前系统活跃的事务id。

作用

可见性判断,即之前做的修改能否对现在的读操作产生影响。也就是说当某个事务在执行快照读的时候,对该记录创建一个read view,把它当做条件,判断当前事务能否看到那个版本,因为有可能读到的是最新的数据,也有可能是历史版本的数据。

遵循原则

遵循可见算法,将被修改数据的最新记录中的DB_TRX_ID与系统其他活跃的事务ID去对比。

可见性规则

read view有三个全局属性:

  1. trx_list:一个数值列表,用来维护read view生成时刻系统正在活跃的事务ID。
  2. up_limit_id:记录trx_list列表中最小的事务ID。
  3. low_limit_id:read view生成时刻系统尚未分配的下一个事务ID(下一个事务的最新ID)
    具体规则:
  1. 判断TRX_ID<UP_LIMIT_ID是否成立,如果成立,表名生成该版本的事务在当前事务生成read view前以及提交,则当前事务可以看到TRX_ID所在的记录,如果不成立进入下一个判断。
  2. TRX_ID>=LOW_LIMIT_ID是否成立,成立:表明该版本的事务在当前事务生成readview之后生成,即看不到当前事务;不成立进入下一个判断。
  3. 判断当前事务ID是否存在trx_list中,如果在,表名创建read view生成该版本的时候事务还在活跃,故当前版本不能被访问;如果不在,说明,创建read view的时候,该版本的事务已经提交,说明该版本是可以被访问的。
    在这里插入图片描述
  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值