当前位置: 首页 > article >正文

面试官:谈谈你对MySQL事务的理解

目录

1、什么是事务?

2、为什么需要事务?

3、事务的四大特性(重点)

3.1 原子性

3.2 一致性

3.3 持久性

3.4 隔离性(难点) 

3.4.1 脏读数据

3.4.2 不可重复读

3.4.3 幻读问题

3.4.4 MySQL 提供的四个隔离级别


1、什么是事务?

事务指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部失败,在不同的环境中,都可以有事务。对应数据库中,就是数据库事务!

简单来说:事务是属于能够把多个 SQL 给打包到一起的,变成一个整体。

这里举一个很简单的例子,篮球哥总在学校操场看到有小伙子跟妹子表白,大概就是地上铺上花瓣,摆好爱心蜡烛,买上一束美丽的鲜花,最后跟妹子深情表白。

那么请问,这个小伙子最终的目的是啥?当然是跟妹子谈恋爱!!!

于是铺鲜花,摆爱心蜡烛,送鲜花,以及深情表白,最终的目的就是希望妹子成为他女朋友,当小伙子鲜花铺好了,蜡烛摆好了,送鲜花给妹子的时候,妹子不要,转身就走!

那么这种情况下,如果送花失败了,前面的铺垫都没任何意义,更别说后面深情表白了,简直说话机会都不给呀!

所以也就相当于,上述铺鲜花,摆蜡烛,送鲜花,深情告白,这几个步骤缺一不可!也就对应俩结果,要么成功,要么失败!事务也是大概的逻辑,要么操作成功,要么操作失败,绝不可能搞一半!


2、为什么需要事务?

张三是个标准男友,今天是情人节,于是跟往常情人节一样,定个 5:20 的闹钟,准时起床给小美发个 1314 的大红包!可是意外发生了!!!

张三给小美转账 1314,假设在底层数据库中执行下述代码:

 update accout set money = money - 1314 where name = '张三';
 update accout set money = money + 1314 where name = '小美';

上述代码很容易理解,就是两条 sql,分别是使张三的账户减少 1314 元,小美的账户增加 1314 元,可是在执行完第一条 sql 后,对应数据库服务器挂了,或者网络出错了,悲剧发生了!

由于网络故障,张三的钱会减少 1314,而小美钱却没有增加!(没有收到转账)

上述这种情况如何解决?这时就可以使用事务来控制了,保证以上两条 sql 要么全部执行成功,要么全部执行失败!不能执行到一半就不执行了!

全部执行失败是啥意思?执行了一条,再让我全部执行失败?那第一条不是已经执行了吗?

注意:这里确实已经执行了第一条,全部执行失败,是指的会恢复成执行之前的样子,看起来就好像一个都没执行一样,这涉及到一个关键操作 "回滚",把执行过的操作逆向恢复回去,类似于我们常用的 ctrl + z 

于是就可以通过事务把这两条 sql 打包成一个整体,这个操作就称为 "原子性",同时 "原子性" 也是事务最最核心的特性,后续多线程章节加锁也会涉及到相关知识!

原子性:物质由分子构成,分子由原子构成,原子之下?还可以再分吗?虽然现在研究出来了原子还可再分,毕竟当时的人们是认为原子是不可再分的,觉得原子就是世界最小的单位了!因此有很多地方就使用 "原子" 来指代不可再切分的最小操作,事务的原子性也是同理!

解决方案:

注意下述操作,中间的这些 sql 不会立即就执行,而是先攒着,等 commit 再统一执行!

start transaction;
update accout set money = money - 1314 where name = '张三';
update accout set money = money + 1314 where name = '小美';
commit;
  • 开启事务:start transaction;
  • 中间放置要执行的 sql
  • 回滚或提交:rollback/commit; 

注意:rollback 表示全部失败,commit 表示全部成功! 


3、事务的四大特性(重点)

3.1 原子性

原子,不可再分割了,放在一段代码里看,这段代码,要不全部执行成功,要不就全部执行失败,绝不可能出现只执行几行就不执行了!有着 "同生共死" 的感觉,一旦原子操作开始了,就不会受其他线程的印象(学完多线程,共容易理解),原子性是事务的初心!

3.2 一致性

事务执行前或都执行后,都得是数据合法的状态,如果像刚才转账,如果因为过程出错,导致钱丢了的情况!(一致性也是一来原子性来实现的)

3.3 持久性

内存是持久的吗?并不是,关机内存上的数据就会丢失,持久是体现在硬盘上的,硬盘上的数据是持久存在的,而数据库的数据是存储在硬盘上,事务产生的修改,都是会写入硬盘的,即使服务器重启了,要不进行回滚,要不就保证修改成功!

3.4 隔离性(难点) 

隔离从字面上理解,就是隔离开来,确实也是类似的效果,后续内容也是围绕隔离性展开的。

MySQL 服务器,要同时给多个客户端提供服务的,可能会有多个客户端同时发起事务,尤其是多个事务在操作同一个数据库的同一个表的时候,可能会引起一些麻烦(了解了多线程后,更容易理解这个点)

MySQL 给我们提供了4个档位的隔离,要理解这几个隔离的效果,先需要理解下面几个特性的含义:

脏读数据,不可重复读,幻读

当把上述三点理解清楚概念,再看来四个隔离级别,就会更好的理解。

3.4.1 脏读数据

一天下课的时候,张三拿起一页空白的纸,在上面写道:我喜欢小明....刚把 "明" 这个字写完,小王突然走到张三旁边,一看,震惊的捂着嘴巴赶紧跑开了!张三还没注意呢,接着写完后面的字:" 我喜欢小明的铅笔盒,你可以给我也买一个吗?",写完后就把纸递给他女朋友小花...

  

此时就可以把张三想象成事务A,正在写数据,把小王想象成事务B,正在读数据呢!

此时的小王,就把这个读到的数据:"我喜欢小明",在班上传开了,张三也百口难辨啊...

这种情况就称为 "脏读" 问题,也叫做 "脏读数据",不是说这个数据多不好,而是说这个数据是一个有问题的数据,不是一个最终的数据,或是读到了只写了一半的数据,可想而知,脏读是多么危险的一件事!

在上述场景中,张三和小王是俩事务,是完全并发的,没有任何限制,这种前提下,就有可能会出现脏读问题!如何解决脏读问题呢?可以降低并发性,提高隔离性,具体来说就是 "写加锁"。

什么是写加锁?就是当张三在写纸条的时候,搞一把伞,把自己全部遮住,不让别人看,等张三写完了:" 我喜欢小明的铅笔盒,你可以给我也买一个吗?",写完了之后,才能给别人看!

这就相当于对写操作进行了加锁,张三写数据的时候,别人就不能去读数据了,相当于降低了并发程度,提高了隔离性,但降低了一定的效率(小王要等张三写完才能去读),同时也提高了准确性!

3.4.2 不可重复读

此时张三已经警惕了不少,已经针对写加锁了(写数据的时候,别人不能读我写的数据)。

假设有这样一种情况,张三写完纸条后,跟小王说,你可以看了,小王于是看到了张三写的纸条了,但是张三一惊,坏了,我怎么能让我女朋友给我买铅笔盒呢?肯定是我给她买呀!

于是在小王看纸条数据的时候,张三当着小王的面给擦了,改成了:" 我喜欢小明的铅笔盒,我也给你买一个吧 ",这是小王很纳闷,我两次读到的数据都不一样啊?哪个才是正确的呢?这一下把小王给搞糊涂了...

在一个事务中,连读两次读到的数据,结果不一致,这就是不可重复读!

如何解决呢?给读操作也加锁,就好比小王看纸条的时候拿在手上看,不让张三修改内容了!

那么这样一来,两个事务之间的并发程度又降低了,隔离性又进一步提高了,运行速度又变慢了,数据的准确性也提高了!(至少小王不会弄混淆,将错就错吧)

3.4.3 幻读问题

当前上述已经针对了读和写加锁,张三写数据的时候,小王不能读,小王读数据的时候张三不能写(针对同一张纸 -> 文件)。

假设张三看到小王在读他写的纸条了,这时候他也不能对纸条增加内容,于是又拿了一张纸条,写上:" 小美,我爱你!",此时读纸条的小王虽然纸条的内容没有改变,但是咋又多了一张呢?

放在计算机文件来说,此时张三可以删除或增加其他文件,只是不能对小王正在操作的文件进行其他操作。

这个问题就称为幻读问题,在同一个事务中,两次读到的结果集不同,称为幻读

要想解决幻读,只能串行化,彻底舍弃并发!只要小王在读纸条,我只能坐着不动。

对于什么是并发,什么是串行,后续多线程会讲解,此处想了解的小伙伴可以查阅其他资料。

3.4.4 MySQL 提供的四个隔离级别

● read uncommitted

这个级别不做任何限制,事务之间都是随意执行的,并发程度最高,隔离性最低,会产生脏读+不可重复度+幻读的问题

● read committed

对写操作加锁了,并发程度降低了,隔离性提高了,解决的脏读的问题,但可能存在不可重复读+幻读的问题

● repeatable read (默认)

对写和读都加锁了,并发程度又降低了,隔离性又提高了,解决了脏读+不可重复度的问题,但可能会出现幻读问题

● serializable

严格串行化,并发成都最低(串行执行),隔离性最高,解决了脏读+不可重复读+幻读问题,执行速度也相对上面更慢。

总结:

隔离性越高,意味着事务的并发程度越低,执行效率是越慢,但数据的准确性是越高的(跟钱有关的业务)

隔离性越低,意味着事务的并发程度越搞,执行效率是越快 ,但数据的准确性是越低的(文章浏览量,某音点赞数)

开发中,就可以根据需求场景,来确定使用哪个隔离级别,可以通过 mysql 配置文件来进行调整


下期预告:【MySQL】JDBC 编程 


http://www.kler.cn/a/6478.html

相关文章:

  • workman服务端开发模式-应用开发-gateway长链接端工作原理
  • 分布式系统架构5:限流设计模式
  • spring学习(spring-DI(setter注入、构造器注入、自动装配方式))
  • 深入浅出支持向量机(SVM)
  • netcore 集成Prometheus
  • 线程知识总结(一)
  • 初识设计模式 - 适配器模式
  • 【python设计模式】8、桥接模式
  • Python入门教程+项目实战-7.2节: 循环控制结构
  • 【Python入门第四十二天】Python丨NumPy 数组裁切
  • 自定义starter
  • 【Ruby学习笔记】4.Ruby 类和对象及类案例
  • OBProxy 路由策略与使用运维-常见问题
  • FIFO的工作原理及其设计
  • 哈利波特c++千行代码
  • C语言程序环境和预处理
  • USB抓包分析
  • Spring Security
  • 【C语言蓝桥杯每日一题】—— 递增序列
  • C 学习笔记 —— 结构(二)
  • 【面试】互联网相关面试题
  • 操作系统结构
  • 【C语言学习】预处理命令
  • 【从零开始学习 UVM】10.7、UVM TLM —— TLM Fifo [uvm_tlm_fifo]
  • [windows-rs]Rust 调用 Windows API
  • 2023-4-1刷提情况