MySQL MVCC

隔离级别定义了事务必须与其他事务进行资源或数据更新相隔离的程度,MySQL InnoDB 事务默认采用可重复读隔离级别,其中可重复读通过 MVCC 实现。

MVCC :Muit-Version Cnncurrency Control,多版本并发控制,它是一种并发控制的方法,在数据库管理系统中实现对数据库的并发访问。

使用 MVCC 的主要原因在于优化性能:如果为了保证同步任何操作都加锁,数据库加解锁的消耗会很大的。为了优化这部分性能,提出了 MVCC 的概念,通过它实现部分场景下不加锁也能保证同步。

MVCC 实现:InnoDB 会在每条记录后面增加三个隐藏字段:

  • DB_ROW_ID:行 ID,随着插入操作单调递增,如果数据包含主键,则不会创建该行
  • DB_TRX_ID:记录插入或更新该行的事务 ID
  • DB_ROLL_PTR:回滚指针,指向 undo log,通过该指针找到修改前的信息,存在多个版本时形成链表

此时对于不同的数据库操作,InnoDB 执行不同的策略:

  • Insert:创建数据的同时,将执行 insert 操作的事务 ID 赋值给 DB_TRX_ID
  • update:将原数据写入 undo log,将执行 update 操作的事务 ID 赋值给 DB_TRX_ID,并将 DB_ROLL_PTR 指向 undo log
  • delete:删除操作实际就是特殊的更新,新增额外标识位 delete_bit 标识已删除

在 RR(Repeatable Read:可重复读)级别下,每开启一个事务,系统给事务分配一个事务 ID。当该事务第一次执行 select 操作时,生成当前时间点的事务快照 ReadView,ReadView 包含以下属性:

  • trx_ids:生成 ReadView 时还未执行事务提交的活跃事务 ID 列表
  • up_limit_id:trx_ids 中最小的那个
  • low_limit_id:生成 ReadView 时系统将要分配给下一个事务的id值
  • creator_trx_id:生成 ReadView 的事务 ID

通俗点来说,通过 up_limit_id 和 low_limit_id 标记了当前事务处理期间,最早存在的事务和最晚创建的事务。通过这两个属性可以简化判断过程,只需根据每行字段的 DB_TRX_ID 字段和 ReadView 属性做对比即可:

  • 如果数据的 DB_TRX_ID 值和 ReadView creator_trx_id 值相等,说明这条数据被当前事务创建或修改,该版本可以被当前事务访问
  • 如果数据的 DB_TRX_ID 值小于 ReadView up_limit_id 值,说明这条数据在当前事务创建前处理完毕,该版本可以被当前事务访问
  • 如果数据的 DB_TRX_ID 值大于 ReadView low_limit_id 值,说明这条数据在当前事务创建后才创建,该版本不能被当前事务访问
  • 如果数据的 DB_TRX_ID 处于 up_limit_id 和 low_limit_id 之间,判断 DB_TRX_ID 是否在 trx_ids 中,如果在,说明当前事务还没有提交,该版本不能访问,否则可以访问

在判断时,每次先拿最高版本比对,依次往前找,直到找到一个可以被当前事务看到的版本。以上内容只针对 RR 级别,在 RC(Read commited 读已提交)级别下,绝大多数操作和 RR 相同,唯一区别在于 RC 操作每次执行 select 都创建新的 ReadView,而 RR 只在事务开启第一次执行 select 操作时创建一次,这也是 RC 不能解决可重复读的原因


之前我们提到,RR 可以解决脏读、可重复读,不能解决幻读。

脏读:读取到其它事务还没有提交的操作
可重复读:对于同一条数据,同一个事务前后读取的结果不一致
幻读:对于范围查询,同一个事务前后查询到的结果条数不一致

提到幻读我们必须引入快照读和当前读的概念:

  • 快照读:就是普通读,普通的 select 语句,基于 ReadView 实现
  • 当前读:加锁读取数据的最新版本,insert、update、delete、select … lock in share mode 等

对于快照读操作,由于快照 ReadView 在事务开启时创建,必然不会产生幻读问题。对于当前读,需要加锁来解决。MySQL InnoDB RR 级别下默认开启 Gap 锁,Gap 锁可以解决幻读,也就是说 MySQL RR 是可以解决幻读的,只是 SQL 标准规范中解决不了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值