【面试官不讲武德系列】面试官一口气问了MySQL事务,Java资料下载

【面试官不讲武德系列】面试官一口气问了MySQL事务,Java资料下载,第1张

【面试官不讲武德系列】面试官一口气问了MySQL事务,Java资料下载

面试官:你是怎么理解InnoDB引擎中的事务的?

候选者:在我的理解下,事务可以使「一组 *** 作」要么全部成功,要么全部失败

候选者:事务其目的是为了「保证数据最终的一致性」。

候选者:举个例子,我给你发支付宝转了888块红包。那自然我的支付宝余额会扣减888块,你的支付宝余额会增加888块。

候选者:而事务就是保证我的余额扣减跟你的余额增添是同时成功或者同时失败的,这样这次转账就正常了

面试官:嗯,那你了解事务的几大特性吗?

候选者:嗯,就是ACID嘛,分别是原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。

候选者:原子性指的是:当前事务的 *** 作要么同时成功,要么同时失败。原子性由undo log日志来保证,因为undo log记载着数据修改前的信息。

候选者:比如我们要 insert 一条数据了,那undo log 会记录的一条对应的 delete 日志。我们要 update 一条记录时,那undo log会记录之前的「旧值」的update记录。

候选者:如果执行事务过程中出现异常的情况,那执行「回滚」。InnoDB引擎就是利用undo log记录下的数据,来将数据「恢复」到事务开始之前

候选者:一致性我稍稍往后讲,我先来说下隔离性

面试官:嗯…

候选者:隔离性指的是:在事务「并发」执行时,他们内部的 *** 作不能互相干扰。如果多个事务可以同时 *** 作一个数据,那么就会产生脏读、重复读、幻读的问题。

候选者:于是,事务与事务之间需要存在「一定」的隔离。在InnoDB引擎中,定义了四种隔离级别供我们使用:

候选者:分别是:read uncommit(读未提交)、read commit (读已提交)、repeatable read (可重复复读)、serializable (串行)

候选者:不同的隔离级别对事务之间的隔离性是不一样的(级别越高事务隔离性越好,但性能就越低),而隔离性是由MySQL的各种锁来实现的,只是它屏蔽了加锁的细节。

候选者:持久性指的就是:一旦提交了事务,它对数据库的改变就应该是永久性的。说白了就是,会将数据持久化在硬盘上。

候选者:而持久性由redo log 日志来保证,当我们要修改数据时,MySQL是先把这条记录所在的「页」找到,然后把该页加载到内存中,将对应记录进行修改。

候选者:为了防止内存修改完了,MySQL就挂掉了(如果内存改完,直接挂掉,那这次的修改相当于就丢失了)。

候选者:MySQL引入了redo log,内存写完了,然后会写一份redo log,这份redo log记载着这次在某个页上做了什么修改。

候选者:即便MySQL在中途挂了,我们还可以根据redo log来对数据进行恢复。

候选者:redo log 是顺序写的,写入速度很快。并且它记录的是物理修改(xxxx页做了xxx修改),文件的体积很小,恢复速度也很快。

候选者:回头再来讲一致性,「一致性」可以理解为我们使用事务的「目的」,而「隔离性」「原子性」「持久性」均是为了保障「一致性」的手段,保证一致性需要由应用程序代码来保证

候选者:比如,如果事务在发生的过程中,出现了异常情况,此时你就得回滚事务,而不是强行提交事务来导致数据不一致。

![](https://img-blog.csdnimg.cn/img_convert/6d81896d3909bf308f18445f8f28b08f.png

《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》

【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享

)

面试官:嗯,挺好的,讲了蛮多的

面试官:刚才你也提到了隔离性嘛,然后你说在MySQL中有四种隔离级别,能分别来介绍下吗?

候选者:嗯,为了讲清楚隔离级别,我顺带来说下MySQL锁相关的知识吧。

候选者:在InnoDB引擎下,按锁的粒度分类,可以简单分为行锁和表锁。

候选者:行锁实际上是作用在索引之上的(索引上次已经说过了,这里就不赘述了)。当我们的SQL命中了索引,那锁住的就是命中条件内的索引节点(这种就是行锁),如果没有命中索引,那我们锁的就是整个索引树(表锁)。

候选者:简单来说就是:锁住的是整棵树还是某几个节点,完全取决于SQL条件是否有命中到对应的索引节点。

候选者:而行锁又可以简单分为读锁(共享锁、S锁)和写锁(排它锁、X锁)。

候选者:读锁是共享的,多个事务可以同时读取同一个资源,但不允许其他事务修改。写锁是排他的,写锁会阻塞其他的写锁和读锁。

候选者:我现在就再回到隔离级别上吧,就直接以例子来说明啦。

面试官:嗯…

候选者:首先来说下read uncommit(读未提交)。比如说:A向B转账,A执行了转账语句,但A还没有提交事务,B读取数据,发现自己账户钱变多了!B跟A说,我已经收到钱了。A回滚事务【rollback】,等B再查看账户的钱时,发现钱并没有多。

候选者:简单的定义就是:事务B读取到了事务A还没提交的数据,这种用专业术语来说叫做「脏读」。

候选者:对于锁的维度而言,其实就是在read uncommit隔离级别下,读不会加任何锁,而写会加排他锁。读什么锁都不加,这就让排他锁无法排它了。

候选者:而我们又知道,对于更新 *** 作而言,InnoDB是肯定会加写锁的(数据库是不可能允许在同一时间,更新同一条记录的)。而读 *** 作,如果不加任何锁,那就会造成上面的脏读。

候选者:脏读在生产环境下肯定是无法接受的,那如果读加锁的话,那意味着:当更新数据的时,就没办法读取了,这会极大地降低数据库性能。

候选者:在MySQL InnoDB引擎层面,又有新的解决方案(解决加锁后读写性能问题),叫做MVCC(Multi-Version Concurrency Control)多版本并发控制

候选者:在MVCC下,就可以做到读写不阻塞,且避免了类似脏读这样的问题。那MVCC是怎么做的呢?

候选者:MVCC通过生成数据快照(Snapshot),并用这个快照来提供一定级别(语句级或事务级)的一致性读取

候选者:回到事务隔离级别下,针对于 read commit (读已提交) 隔离级别,它生成的就是语句级快照,而针对于repeatable read (可重复读),它生成的就是事务级的快照。

候选者:前面提到过read uncommit隔离级别下会产生脏读,而read commit (读已提交) 隔离级别解决了脏读。思想其实很简单:在读取的时候生成一个"版本号",等到其他事务commit了之后,才会读取最新已commit的"版本号"数据。

候选者:比如说:事务A读取了记录(生成版本号),事务B修改了记录(此时加了写锁),事务A再读取的时候,是依据最新的版本号来读取的(当事务B执行commit了之后,会生成一个新的版本号),如果事务B还没有commit,那事务A读取的还是之前版本号的数据。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5672602.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存