关于javascript:面试被吊打系列-事务隔离级别

30次阅读

共计 2638 个字符,预计需要花费 7 分钟才能阅读完成。

小张灰溜溜去面试,后果被面试官吊打!

小张:面试官,你好。我是来加入面试的。

面试官:你好,小张。我看了你的简历,精通 MySQL 数据库。那你必定晓得事务吧,你能说说 事务有哪些个性 吗?

小张:一个事务有 4 个个性,即 ACID。

  • 原子性(Atomicity): 事务开始后的所有操作,要么全副胜利要么全副失败。
  • 一致性(Consistency): 事务开始前后数据库的完整性束缚没有被毁坏,比方:A 向 B 转钱,不可能呈现 A 扣了钱,B 没收到钱。
  • 隔离性(Isolation):多个事务并发拜访时,事务之间是隔离的。
  • 持久性(Durability):事务实现后,事务对数据库的操作被保留在了数据库,不能回滚。

面试官:嗯,答的很对。那你说说事务有哪几种隔离级别呢?

小张:事务隔离级别从高到低有四种隔离级别,别离是:串行化(SERIALIZABLE)、可反复读(REPEATABLE READ)、读提交(READ COMMITTED)、读未提交(READ UNCOMMITTED)。

面试官:嗯嗯,那你能说说这四种隔离级别别离会造成什么问题吗?

(小张窃喜,我就晓得你要这么问,还好我平时关注了‘JAVA 日知录’的公众号)

小张:好的,面试官。

如果数据库采纳 读未提交(READ UNCOMMITTED)这种隔离级别,会造成 脏读。事务还没提交他人就能看到,这样就不能保障你读取到的数据是最终的数据,万一他人把事务回滚了,那就呈现了脏数据问题。

读提交(READ COMMITTED)是指一个事务只能读取到其余事务曾经提交了的数据,这样就不会呈现脏读的问题,然而它会带来」不可反复读 的问题。比方 A 事务 将一个人的姓名从张三改成李四,B 事务在 A 事务提交之前读取到的是张三,然而在 A 事务提交之后就变成了李四。

可反复读(REPEATABLE READ):可反复读是为了解决 READ COMMITTED 带来的不可反复读问题,指的是事务不会读取到其余事务对已有数据的批改,即便数据曾经提交了。也就是说事务开始读取到的是什么,在事务提交之前的任意时刻,这些数据都一样。尽管解决了不可反复读问题,然而他又会带来 幻读 的问题。比方 A 事务将张三批改成李四,B 事务再插入一个名叫李四的用户,此时事务 A 再查找名叫李四的用户会发现多了一条,呈现了 2 个李四,这就是幻读。

串行化(SERIALIZABLE):解决了下面呈现的所有问题,然而它效率最差,它将事务的执行变成程序执行了。

面试官:答复的不错,那你晓得 MySQL 的默认隔离级别是什么吗

小张:Mysql 默认的隔离级别是REPEATABLE READ,Oracle 则采纳的是READ COMMITTED

面试官:然而咱们应用 MySQL 的时候并没有呈现幻读啊,怎么解决的?

小张擦了擦汗,开始有点缓和了:额,InnoDB 次要是利用锁来解决幻读问题的。

面试官:对,是采纳了锁,那么具体怎么实现的呢?

小张:我 … 我忽然有点事,我先回去了。

面试官:要理解 InnoDB 怎么解决幻读得先晓得 InnoDB 有哪几种锁。

  • Record Lock:单个行记录上的锁
  • Gap Lock:间隙锁,锁定一个范畴,而非记录自身,遵循左开右闭准则
  • Next-Key Lock:联合 Gap Lock 和 Record Lock,锁定一个范畴,并且锁定记录自身。次要解决的问题是 REPEATABLE READ 隔离级别下的幻读。

留神,如果走惟一索引,那么 Next-Key Lock 会降级为 Record Lock,即仅锁住索引自身,而不是范畴。也就是说 Next-Key Lock 前置条件为事务隔离级别为 RR 且查问的索引走的非惟一索引、主键索引。

上面咱们通过具体的例子来模仿下面呈现的幻读问题:

`CREATE TABLE T (id int ,name varchar(50),f_id int,PRIMARY KEY (id), KEY(f_id)) ENGINE=InnoDB DEFAULT CHARSET=utf8`
`insert into T SELECT 1,'张三',10;`
`insert into T SELECT 2,'李四',30;`

InnoDB 在数据库中会为索引保护一套 B + 树,用来疾速定位行记录。B+ 索引树是有序的,所以会把这张表的索引宰割成几个区间。

事务 A 执行如下语句,须要将张三批改成李四。

`select * from t;`
`update t set name = '李四' where f_id = 10;`

这时 SQL 语句走非惟一索引,因而应用 Next-Key Lock 加锁,不仅会给 f_10=10 的行加上行锁,而且还会给这条记录的两边增加上间隙锁,即 (-∞,10]、(10,30] 这 2 个区间都加了间隙锁。

此时如果 B 事务要执行如下语句,都会报错[Err] 1205 - Lock wait timeout exceeded; try restarting transaction

`INSERT INTO T SELECT 3,'王五',10;  -- 满足行锁,执行阻塞 `
`INSERT INTO T SELECT 4,'赵六',8;   -- 满足间隙锁,执行阻塞 `
`INSERT INTO T SELECT 5,'孙七',18;  -- 满足间隙锁,执行阻塞 `

不仅插入 f_id = 10 的记录须要期待事务 A 提交,f_id <1010< f_id <30 的记录也无奈实现,而大于等于 30 的记录则不受影响,这足以解决幻读问题了。

刚刚讲的是 f_id 是索引列的状况,那么如果 f_id 不是索引列会怎么样呢?

这时候数据库会为整个表加上间隙锁。所以,如果是没有索引的话,不论 f_id 是否大于等于 30,都要期待事务 A 提交才能够胜利插入。

面试官:好了,各位看官敌人们,事务的隔离级别这个面试点你们分明了吗?心愿你们的面试不会被这个问题难倒哟~

小张:学到了学到了,我下次再来。(连忙回去把简历上的精通数据库给删掉。)

以上,心愿对你有所帮忙!


这里为大家筹备了一份小小的礼物,关注公众号,输出如下代码,即可取得百度网盘地址,无套路支付!

001:《程序员必读书籍》
002:《从无到有搭建中小型互联网公司后盾服务架构与运维架构》
003:《互联网企业高并发解决方案》
004:《互联网架构教学视频》
006:《SpringBoot 实现点餐零碎》
007:《SpringSecurity 实战视频》
008:《Hadoop 实战教学视频》
009:《腾讯 2019Techo 开发者大会 PPT》

010:微信交换群

正文完
 0