前言
我们知道MySQL的事务四个特性,原子性、一致性、隔离性、持久性,今天我们来重点学习隔离性,这也是面试中经常会问到的问题。
1 事务并发所带来的问题
在隔离性之前先看事务并发时会产生什么问题。
1.1 脏读
脏读是事务A读取了事务B未提交的数据,然后事务B并没有提交事务而是回滚了事务,这样就会造成事务A读取了一个无效且没有意义的数据。
简而言之:一个事务读取了另一个事务未提交的数据,在读未提交级别会有这样的情况。
1.2 不可重复读
不可重复读是事务A中相同的查询,产生了不同的结果。
造成这种结果的原因是事务A第一次查询之后,事务B修改了数据并且提交事务,这个时候事务A又查询了一次数据,这个时候读取到了事务B修改的结果。
简而言之:一个事务读取了另一个事务已提交的数据,在读未提交和读已提交都会有不可重复度的问题。
1.3 幻读
The so-called phantom problem occurs within a transaction when the same query produces different sets of rows at different times.
官网开头有这样一句话,大意是:当同一查询在不同时间生成不同的行集时,事务中就会出现所谓的幻影问题。
具体操作:对于两个事务T1、T2,T1从表中读取数据,然后T2进行了INSERT操作并提交,当T1’再次读取的时候,结果不一致的情况发生。
简而言之:一个事务读取了另一个事务新插入的行,导致两次相同查询不同。
参考文档:官方文档幻读说明
1.4 实践
1.4.1 基础准备
建表语句:
CREATE TABLE `t` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`a` int(11) DEFAULT NULL,
`b` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
新建数据:
1.4.2 不可重复读实践
实践之前先更改下隔离级别
#查询数据隔离级别
SELECT @@tx_isolation;
#设置隔离级别为读已提交
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
session A | session B | |
---|---|---|
T1 | begin; select * from t; | |
T2 | update t set b = 300 where a = 30; | |
T3 | select * from t; |
结果1:
结果2:
可以看到事务A中,两次相同的查询结果并不相同,原因是事务A读了事务B修改的数据。
1.4.3 幻读实践
实践之前先更改下隔离级别
#查询数据隔离级别
SELECT @@tx_isolation;
#设置隔离级别为读已提交
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
session A | session B | |
---|---|---|
T1 | begin; select * from t; | |
T2 | insert into t (a,b) values (60,60); | |
T3 | select * from t; |
结果1:
结果2:
可以看到事务A中,两次相同的查询结果并不相同,原因是事务A读了事务B新增的数据,这新增的行为幻影行。
2 隔离级别
事务隔离是数据库处理的基础之一。隔离级别是在多个事务同时进行更改和执行查询时微调结果的性能和可靠性、一致性和可再现性之间的平衡的设置。
2.1 Read Uncommitted(读取未提交内容)
- 在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。
- 读取未提交的数据,也被称之为脏读(Dirty Read)。
2.2 Read Committed(读取提交内容)
它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。
2.3 Repeatable Read(可重复读)
这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。
3.4 Serializable(可串行化)
这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。
3.5 四种隔离级别
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(read-uncommitted) | 有 | 有 | 有 |
读已提交(read-committed) | 无 | 有 | 有 |
可重复读(repeatable-read) | 无 | 无 | 有 |
串行化(serializable) | 无 | 无 | 无 |