数据库隔离级别与MVCC多版本并发控制

数据库隔离级别

这部分主要看的是ACID特性中的隔离性。隔离级别越高,事务越安全,但是并发性会变差。

数据库的三种隔离问题:

  • 脏读:事务A更新了数据,但未提交,事务B读取了这个更新后的数据。随后事务A回滚,结果导致事务B读取的是脏数据,因此叫脏读。
  • 不可重复读:事务A对同一个数据先后读两次。第一次读取完毕后,事务B更新了这个数据,随后事务A进行第二次读取,发现这个数据转眼间竟然前后不一致。这就是不可重复读。(重点在修改)
  • 幻读:事务A查询或者修改数据表的符合范围条件的数据记录,但期间事务B向表中这个范围内插入了一条新的数据。则事务A操作完成后,发现竟然还有一条没有修改的数据行,就像发生了幻觉一样,所以叫幻读。(重点在新增)

数据库有四种隔离级别(由低到高):

  • 读未提交:可以读到未提交的数据。会出现脏读、不可重复读、幻读的问题。一般不使用这种隔离级别。
  • 读提交:只能读到已经提交了的数据。可以防止脏读,但不能防止不可重复读和幻读。
  • 可重复读:可以保证一个事务中对于同一行记录的前后多次读取是一致的,可以防止脏读和不可重复读,但不能防止幻读,因为这个隔离级别没有限制新增操作。
  • 可串行化:是完全服从ACID的最高隔离级别。所有的事务依次逐个执行,完全舍弃并发,当然没有并发时的隔离问题,但效率很低。

在MySQL中,默认的隔离级别是可重复读,并且使用间隙锁解决了幻读问题。也就是说,mysql默认解决了脏读、不可重复读和幻读的问题。

MYSQL有两种方式实现可重复读的隔离级别

  1. 一种是基于锁的并发控制。MySQL可以通过加锁(事务结束才释放)来实现可重复读级别。
  2. 另一种是MVCC(多版本并发控制)。MVCC最大的优势是写加锁,但读不加锁,使得读写不阻塞,在读多写少的应用场景下能够显著提高系统的并发性能。

MySQL 行锁、两阶段锁协议、死锁以及死锁检测

MVCC 多版本并发控制

读未提交与脏读

读未提交会导致脏读的问题,因为这个级别没有加锁。加共享锁和排他锁可以解决脏读的问题,但是会使读操作和写操作无法并发执行,降低效率。

MVCC解决脏读的方法类似 copyonwrite,MVCC允许每行数据有多个版本,并且对于写操作和读操作有限制

  • 写操作不直接在原数据上修改,而是拷贝一份数据出来,在拷贝数据上修改,写操作完成并且提交后再原子性地替换数据并且加上新的版本号。
  • 读操作只能读取到读操作执行时的当前版本及之前的旧版本。

假设事务A要读数据时,事务B正在写这行数据而且未提交,则此时数据上只有旧的版本号,读操作不会读到事务B未提交的数据修改,因此MVCC可以解决脏读问题,此时隔离级别已经提升至读提交级别。

读提交与不可重复读

读提交虽然解决了脏读的问题,但是仍会有不可重复读的问题。

上面MVCC可以使读操作和写操作并发执行,但是仅限于每个事务都只有一条语句的情况下。假设事务A对同一个数据先后读两次,期间事务B修改数据完毕并且提交,则第二次读操作执行时版本号已更新,会读出修改后的数据,导致两个语句读出来的数据前后不一致。

所以关键在于,前面MVCC对读操作的限制是以语句为单位的,限制读操作只能读到该语句执行时以及之前的版本号。而MVCC对于不可重复读的解决方法是,对读操作的限制提升为以事务为单位,即一个事务里的所有读操作都只能读事务开始时以及之前的版本号。这样即使期间另一个事务更新的版本号,后面的读操作也只能读到旧的数据,从而使读到的数据前后一致。此时隔离级别已经提升至可重复读级别。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值