【MySQL】——一篇文章带你彻底弄懂事务,循序渐进!(包含MVCC)

目录

前言:

事务在mysql中占据非常重要的地位,是十分重要的知识。文章从事务的介绍到事务的特性,再到事务的隔离性以及隔离级别。并介绍了MVCC及其实现原理。

一.事务

1.事务的介绍

2.事务的特性

事务具有以下四个特性:

二. 事务的隔离性

1.可能出现的问题

1.脏读

2.不可重复读

3.幻读

2.事务的隔离级别

三.MVCC

1.介绍

2.MVCC实现原理

1.隐藏字段:

2.undo log

3.ReadView

1.介绍

2.访问规则

3.RC隔离级别下:

4.RR隔离级别下:

四.幻读

1.幻读产生的本质是什么?

2.怎么解决幻读?


一.事务

1.事务的介绍

小故事引入:

这里有一个非常经典的关于事务的故事:转账

张三给李四转账1000元,当然非常正常的结果就是张三的账户-1000元,而李四的账户+1000元,这是显而易见的。

但在这时发生了一个意外,在运行在第三步前的时候发生了异常,结果便是第三步并没有执行,也就是说张三的账户余额-1000元,但李四的钱并没有+1000元,这就出现了问题。

那我们如何解决这个问题呢?这里我们就引入了事务的概念

在步骤开始前加入事务,在结束后提交事务,这样我们就保证了里面的步骤要么同时成功,要么同时失败。当抛出异常的时候,我们就会进行回滚事务,将数据恢复成之前的状态。

现在我们再来讲一下事务的概念:    

      事务是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败。

2.事务的特性

    事务是由 MySQL 的引擎来实现的,我们常见的 InnoDB 引擎它是支持事务的。不过并不是所有的引擎都能支持事务,比如 MySQL 原生的 MyISAM 引擎就不支持事务,也正是这样,所以大多数 MySQL 的引擎都是用 InnoDB。

   现在我们知道了事务是什么,它的概念,那么一个东西一定具有它的特性,它的特性是什么样的呢?当然大家可能都或多或少的脑子里会蹦出四个字母——ACID。那么它究竟是什么呢?为什么事务具有这样的特性?InnoDB又是如何实现它们的呢?这是我们接下来需要明白的问题。

事务具有以下四个特性:

  • 原子性(Atomicity):事务是不可分割的最小操作单元,要么全部成功,要么全部失败。

例子:还是上面转账这个例子,张三转账给李四,张三扣1000,李四加    1000,如果中间发生异常,那么会回滚到事务开始前的状态,张三和李四   的钱都没变。

  • 一致性(Consistency):事务完成时,必须使所有的数据都保持一致状态。

 例子:用户A和用户 B在银行分别有 800 元和 600 元,总共 1400元,用户A给用户 B转账 200 元分为两个步骤,从 A的账户扣除200 元和对 B的账户增加 200 元。一致性就是要求上述步骤操作后最后的结果是用户 A 还有 600 元,用户 B有 800 元,总共 1400 元,而不会出现用户 A 扣除了 200元,但用户 B未增加的情况(该情况,用户 A和 B均为 600 元,总共1200 元)。

  • 隔离性(lsolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行

数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交又执行而导致数据的不一致,因为多个事务同时使用相同的数据时,不会相互干扰,每每个事务都有一个完整的数据空间,对其他并发事务是隔离的。也就是说,消费者购买商品这个事务,是不影响其他消费者购买的。

  • 持久性(Durabiity):事务一旦提交或回滚,它对数据库中的数据的改变就是永久的。即使统统发生了故障,也不会丢失。

InnoDB 引擎通过什么技术来保证事务的这四个特性的呢?

  • 持久性是通过 redo log(重做日志)来保证的
  • 原子性是通过 undo log(回滚日志)来保证的;
  • 隔离性是通过 MVCC(多版本并发控制)或锁机制来保证的。
  • 一致性则是通过持久性+原子性+隔离性来保证;

这次将重点介绍事务的隔离性,这也是面试时最常问的知识的点。

为什么事务要有隔离性,我们就要知道并发事务时会引发什么问题?

二. 事务的隔离性

MySQL 服务端是允许多个客户端连接的,这意味着 MySQL 会出现同时处理多个事务的情况。那么在同时处理多个事务的时候,就可能出现脏读(dirtyread)、不可重复读(non-repeatableread)、幻读(phantom read)的问题。


接下来,通过举例子给大家说明,这些问题是如何发生的。

1.可能出现的问题

1.脏读

2.不可重复读

3.幻读

2.事务的隔离级别

前面我们提到,当多个事务并发执行时可能会遇到「脏读、不可重复读、幻读」的现象,这些现象会对事务的一致性产生不同程序的影响。
脏读:            读到其他事务未提交的数据;
不可重复读: 前后读取的数据不一致;
幻读:            前后读取的记录数量不一致;

所以,要解决脏读现象,就要升级到「读提交」以上的隔离级别;

          要解决不可重复读现象,就要升级到[可重复读」的隔离级别,要解决幻读现象不建议将隔离级别升级到「串行化」。
不同的数据库厂商对 SQL标准中规定的 4种隔离级别的支持不一样,有的数据库只实现了其中几种隔离级别,我们讨论的 MySQL虽然支持4种隔离级别,但是与SQL标准中规定的各级隔离级别允许发生的现象却有些出入。
MySQL 在「可重复读」RR隔离级别下,可以很大程度上避免幻读现象的发生(注意是很大程度避免,并不是彻底避免),所以 MySQL并不会使用「串行化」隔离级别来避免幻读现象的发生,因为使用「串行化」隔离级别会影响性能。

三.MVCC

1.介绍


多版本并发控制,是用来解决数据并发场景中并发读写问题的。

2.MVCC实现原理

取决于3个内容:隐藏字段,undo log,readview。

1.隐藏字段:

2.undo log

回滚日志,在insert、update、delete的时候产生的便于数据回滚的日志当insert的时候,产生的undolog日志只在回滚时需要,在事务提交后,可被立即删除。

而update、delete的时候,产生的undo log日志不仅在回滚时需要,在快照读时也需要,不会立即被删除。

那么在进行读取数据时,我读的到底是这些版本中的那一个版本呢?引入readview

3.ReadView

1.介绍

ReadView(读视图)是 快照读 SQL执行时MVCC提取数据的依据,记录并维护系统当前活跃的事务(未提交的)id。

2.访问规则

3.RC隔离级别下:

RC隔离级别下,在事务中每一次执行快照读时生成ReadView。

4.RR隔离级别下:

RR隔离级别下,仅在事务中第一次执行快照读时生成ReadView,后续复用该ReadView。

在RR级别下,可重复读在同一个事务中读取两条相同的数据,当然读的应该是一样的,两个ReadView都一样,当然上述的匹配规则就是一样的,读取的数据当然也是一样的,这样就保证了可重复读。

MVCC的作用就是在快照读时,决定我们读取的是哪一条字段。

四.幻读

1.幻读产生的本质是什么?

来看一个例子吧~

现在事务1 查询年龄为20的数据,好,我们查到了两条

这时事务2 插入一条年龄为20的数据,我再在事务1中查询年龄为20的数据,那么问题来了,我查询到了几条?2还是3?请思考

答:还是两条,当然是两条了!可重复读呀,前面都在聊这个事!

那么这时我在事务1中修改年龄为20的所有数据,修改的是几条?2还是3?请思考

答:这时是3条了,我查的是2条,改的是3条,这就是幻读。因为现在是当前读,它能够读到最新的数据。

现在可以回答幻读的本质了!

幻读的本质

如果事务中都是快照读,那么不会产生幻读的问题,但是快照读和当前读一起使用的时候就会产生幻读问题

2.怎么解决幻读?

加锁(不明白的可以参考这一篇文章:【MySQL】——锁_数据库表的加密-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值