事务隔离级别实现-行锁与MCCC

我们都知道数据库在并发同时执行的时候,就可能出现脏读、不可重复读、幻读的问题,为了解决这些问题,设置了四种事务的隔离级别,分别是

  • 读未提交:A事务【能】看到B事务【未提交】的修改
  • 读已提交:A事务【能】看到B事务【已提交】的修改
  • 可重复读:A事务【不能】看到B事务【已提交】的修改
  • 串行化:所有事务按顺序执行,不能并行

我们以Mysql为例,Mysql是怎么实现这些隔离级别的呢?

1. 通过数据库行锁实现

Mysql的行锁有两种,【读锁】(共享锁)和【写锁】(排它锁)。如果有一行数据如果加了【读锁】,那么这一行数据直到锁释放都加不了【写锁】(阻塞)。这一行加【写锁】的话,那么【读锁】和【写锁】都加不了。

我们假设只用这两种锁来解决上面的问题。那么

隔离级别实现方式
读未提交读写都不加锁
读已提交写加【写锁】(事务结束才释放),读的时候需要加【读锁】(读完就释放【读锁】),等到【写锁】释放才能读到
可重复读写加【写锁】(事务结束才释放),读的时候需要加【读锁】(事务结束才释放),加【读锁】期间如果有数据更新(加写锁)都会阻塞
串行化读写锁的范围都是整张表,无法并行

我们可以看到,加锁是可以实现上面的隔离界别的,但是有一个问题,就是数据库性能会急剧的下降

2. 通过MVVC实现

Innodb为了解决这个问题,引入了MVCC机制,既多版本并发控制。Mysql的MVVC是利用的回滚日志undolog完成的。这里简单讲一下Mysql的三种日志 redolog、binlog、undolog。redolog和binlog主要用于恢复数据,而undolog主要用于事务回滚。

假设一个值从1被按顺序改成了 2、3、4,在回滚日志里面就会有类似下面的记录

当前值是 4,但是在查询这条记录的时候,不同时刻启动的事务会有不同的 read-view。如图中看到的,在视图 A、B、C 里面,这一个记录的值分别是1、2、4,同一条记录在系统中可以存在多个版本,就是数据库的多版本并发控制(MVCC)。

对于视图(read-view)A,要得到1,就必须将当前值依次执行图中所有的回滚操作得到。同时你会发现,即使现在有另外一个事务正在将 4改成5,这个事务跟 视图 A、B、C 对应的事务是不会冲突的。

隔离级别实现方式
读未提交不加视图,读的始终是最新的
读已提交每次读的时候创建视图
可重复读事务创建时创建视图,整个事务中读都用这个视图读

这里只针对读的情况,对于写的情况还是会加写锁的,而普通读通过MVVC可以不用加读锁了,这样读跟写就不会互相阻塞了(写跟写还是会阻塞的)。另外Mysql的可重复读级别运用了间隙锁可以解决幻读的问题。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值