最全MySQL事务还能这么理解?这回我知道怎么应付面试官了,阿里P8架构师

写在最后

还有一份JAVA核心知识点整理(PDF):JVM,JAVA集合,JAVA多线程并发,JAVA基础,Spring原理,微服务,Netty与RPC,网络,日志,Zookeeper,Kafka,RabbitMQ,Hbase,MongoDB,Cassandra,设计模式,负载均衡,数据库,一致性哈希,JAVA算法,数据结构,加密算法,分布式缓存,Hadoop,Spark,Storm,YARN,机器学习,云计算…

image

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

事务B在同一个事务中执行两次统计操作之间,另一事务insert了一条记录,导致得到的结果不一样,好像发生了幻觉。还有一种情况是事务B更新了表中所有记录的某一字段,之后事务A又插入了一条记录,事务B再去查询发现有一条记录没有被更新,这也是幻读。

2.3.4 不可重复读

不可重复读:一个事务读到了另一个事务已提交的更新数据。
不可重复读,顾名思义,就是在同一个事务中重复读取数据会发生不一致的情况,如下图:

事务B在T2和T5阶段都执行了查询余额的操作,但是每次得到的结果都不一样,这在开发中是不允许的,同一个事务中同样的多次查询,每次返回不一样的结果,让人不免会对数据库的可靠性产生怀疑。

2.3.5 第二类丢失更新

一个事务在提交的时候,覆盖了另一个事务已提交的更新数据。

由上图可以看出,当事务A提交之后,账户余额已经发生了变动,然后事务B还是基于原始金额(即1000)的基础上扣除取款金额的,事务B以提交,就是把事务A的提交给完全覆盖了。此为第二类丢失更新。

注意和第一类丢失更新区分,第一类丢失更新重点在事务B最终撤销了事务,第二类是最终提交了事务。

为了解决这五类问题,MySQL提供了四种隔离级别:

  • Serializable(串行化) :事务之间以一种串行的方式执行,安全性非常高,效率低
  • Repeatable Read(可重复读) :是MySQL默认的隔离级别,同一个事务中相同的查询会看到同样的数据行,安全性较高,效率较好
  • Read Commited(读已提交) :一个事务可以读到另一个事务已经提交的数据,安全性较低,效率较高
  • Read Uncommited(读未提交) :一个事务可以读到另一个事务未提交的数据,安全性低,效率高

3、Repeatable Read

Repeatable Read(可重复读)是MySQL默认的隔离级别,也是使用最多的隔离级别,所以单独拿出来深入理解很有必要。Repeatable Read无法解决幻读(虚读)问题。下面来看一个实例。
首先创建一个表并插入一条记录:

CREATE TABLE student (
id bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT ‘主键’,
stu_id bigint(20) NOT NULL DEFAULT ‘0’ COMMENT ‘学生学号’,
stu_name varchar(100) DEFAULT NULL COMMENT ‘学生姓名’,
created_date datetime NOT NULL COMMENT ‘创建时间’,
modified_date datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT ‘修改时间’,
ldelete_flag tinyint(1) NOT NULL DEFAULT ‘0’ COMMENT ‘逻辑删除标志,0:未删除,2:已删除’,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT=‘学生信息表’;

INSERT INTO student VALUES (1, 230160340, ‘Carson’, ‘2016-08-20 16:37:00’, ‘2016-08-31 16:37:05’, 0);

同样的开启两个事务,如下表所示:

按照上述理论,会出现幻读现象。也就是事务A在T4时间段的查询select会看到事务B提交的新增数据。
但让你失望了。

执行结果如下

和预期的结果并不一致,没有出现幻读现象。

实际上MySQL在Repeatable Read隔离级别下,用MVCC(Multiversion Concurrency Control,多版本并发控制)解决了select普通查询的幻读现象。

具体的实现方式就是事务开始时,第一条select语句查询结果集会生成一个快照(snapshot),并且这个事务结束前,同样的select语句返回的都是这个快照的结果,而不是最新的查询结果,这就是MySQL在Repeatable Read隔离级别对普通select语句使用的快照读(snapshot read)。

快照读和MVCC是什么关系?

MVCC是多版本并发控制,快照就是其中的一个版本。所以可以说MVCC实现了快照读,具体的实现方式涉及到MySQL的隐藏列。MySQL会给每个表自动创建三个隐藏列:

  • DB_TRX_ID:事务ID,记录操作(增、删、改)该数据事务的事务ID
  • DB_ROLL_PTR:回滚指针,记录上一个版本的数据在undo log中的位置
  • DB_ROW_ID:隐藏ID ,创建表没有合适的索引作为聚簇索引时,会用该隐藏ID创建聚簇索引

由于undo log中记录了各个版本的数据,并且通过DB_ROLL_PTR可以找到各个历史版本,并且由DB_TRX_ID决定使用哪个版本(快照)。所以相当于undo log实现了MVCC,MVCC实现了快照读。

如此看来,MySQL的Repeatable Read隔离级别利用快照读,已经解决了幻读的问题。
但是事实并非如此,接下来再看一个例子

事务A在T1的时候生成快照,事务B在T2的时候插入一条数据Luffy,然后提交。在T4的时候把Luffy更新成Katakuri,根据上一个例子的经验,此时事务A是看不到Luffy这条数据的,所以更新也不会成功,并且在T5的时候查询,和T1时候一样,只有Carson和Kata两条数据。

但是,又要让你失望了

执行结果如下

但是执行结果却不是预期的那样,事务A不仅看到了Luffy,还把它成功的改成了Katakuri。即使事务A成功commit之后,再次查询还是这样。

这其实是MySQL对insert、update和delete语句所使用的当前读(current read)。因为涉及到数据的修改,所以MySQL必须拿到最新的数据才能修改,所以涉及到数据的修改肯定不能使用快照读(snapshot read)。由于事务A读到了事务B已提交的新增数据,所以就产生了前文所说的幻读。

那么在Repeatable Read隔离级别是怎么解决幻读的呢?

是通过间隙锁(Gap Lock)来解决的。我们都知道InnoDB支持行锁,并且行锁是锁住索引。而间隙锁用来锁定索引记录间隙,确保索引记录的间隙不变。间隙锁是针对事务隔离级别为Repeatable Read或以上级别而设的,间隙锁和行锁一起组成了Next-Key Lock。当InnoDB扫描索引记录的时候,会首先对索引记录加上行锁,再对索引记录两边的间隙加上间隙锁(Gap Lock)。加上间隙锁之后,其他事务就不能在这个间隙插入记录。这样就有效地防止了幻读的发生。

默认情况下,InnoDB工作在Repeatable Read的隔离级别下,并且以Next-Key Lock的方式对索引行进行加锁。当查询的索引具有唯一性(主键、唯一索引)时,Innodb存储引擎会对Next-Key Lock进行优化,将其降为行锁,仅仅锁住索引本身,而不是范围(除非锁定不存在的值)。若是普通索引,则会使用Next-Key Lock将记录和间隙一起锁定。

使用快照读的查询语句

SELECT * FROM …

使用当前读的语句

SELECT * FROM … lock in share mode
SELECT * FROM … for update
INSERT INTO table …
UPDATE table SET …
DELETE table WHERE …

4、小结

本文主要讲解了MySQL事务的ACID四大特性,undo log和redo log分别实现了原子性和持久性,log持久化的三种方式,数据库并发下的五类问题、四种隔离级别、RR隔离级别下select幻读通过MVCC机制解决、select ... lock in share mode/select ... for update/insert/update/delete 的幻读通过间隙锁来解决。

本文涉及的比较深入,掌握好本文的知识点,让你不仅仅是停留在ACID、隔离级别的层面,在面试中能够化被动为主动,收割大厂offer。

最后

针对最近很多人都在面试,我这边也整理了相当多的面试专题资料,也有其他大厂的面经。希望可以帮助到大家。

下面的面试题答案都整理成文档笔记。也还整理了一些面试资料&最新2021收集的一些大厂的面试真题(都整理成文档,小部分截图)

在这里插入图片描述

最新整理电子书

在这里插入图片描述

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

//bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)收录**

需要这份系统化的资料的朋友,可以点击这里获取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值