理解 MySQL 中的四种隔离级别

数据库事务有不同的隔离级别,不同的隔离级别对锁的使用是不同的,锁的应用最终导致不同事务的隔离级别。(保持怀疑)

幻读

什么是幻读?

幻读不是说两次读取的结果集不同,幻读侧重的是某一次的select操作得到的结果所表征的数据状态无法支撑后续的业务操作。更具体一些:select某记录是否存在,不存在,准备插入此记录,但执行insert时发现此记录已经存在,无法插入,此时就发生了幻读。

实现隔离级别的方式就是加锁。(保持怀疑)

示例(来自网络)

table users: id primary key

事务T1

图片描述
事务T2
图片描述

step1 T1: SELECT * FROM users WHERE id = 1;
step2 T2: INSERT INTO users VALUES (1, ‘big cat’);
step3 T1: INSERT INTO users VALUES (1, ‘big cat’);
step4 T1: SELECT * FROM users WHERE id = 1;

T1 :主事务,检测表中是否有 id 为 1 的记录,没有则插入,这是我们期望的正常业务逻辑。
T2 :干扰事务,目的在于扰乱 T1 的正常的事务执行。
在 RR 隔离级别下,step1、step2 是会正常执行的,step3 则会报错主键冲突,对于 T1 的业务来说是执行失败的,这里 T1 就是发生了幻读,因为 T1 在 step1 中读取的数据状态并不能支撑后续的业务操作,T1:“见鬼了,我刚才读到的结果应该可以支持我这样操作才对啊,为什么现在不可以”。T1 不敢相信的又执行了 step4,发现和 setp1 读取的结果是一样的(RR下的 MMVC机制,因为事务t2在事务t1之后,所以t1看不到t2插入的数据)。此时,幻读无疑已经发生,T1 无论读取多少次,都查不到 id = 1 的记录,但它的确无法插入这条他通过读取来认定不存在的记录(此数据已被T2插入),对于 T1 来说,它幻读了。

MySQL事务隔离级别

查看MySQL事务隔离级别

1.查看当前会话隔离级别
select @@tx_isolation;

2.查看系统当前隔离级别
select @@global.tx_isolation;

3.设置当前会话隔离级别
set session transaction isolatin level repeatable read;

4.设置系统当前隔离级别
set global transaction isolation level repeatable read;

5.命令行,开始事务时
set autocommit=off 或者 start transaction

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 查看当前会话隔离级别
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set, 1 warning (0.00 sec)

# 查看系统当前隔离级别
mysql> select @@global.tx_isolation;
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| REPEATABLE-READ |
+-----------------------+
1 row in set, 1 warning (0.00 sec)

隔离级别的分类

  1. 读未提交 Read Uncommitted(在本次事务中可以读到其他事务中没有提交的数据 - 脏数据)
  2. 读已提交 Read Committed (只能读到其他事务提交过的数据。如果在当前事务中,其他事务有提交,则两次读取结果不同)
  3. 可重复读 Repeatable Read (默认,保证了事务中每次读取结果都相同,而不管其他事物是否已经提交。会出现幻读)
  4. 序列化 Serializable (隔离级别中最严格的,开启一个 serializable 事务,那么其他事务对数据表的写操作都会被挂起)

参考文献

[1]mysql 幻读的详解、实例及解决办法:https://segmentfault.com/a/1190000016566788
[2]理解 MySQL 中的四种隔离级别:https://learnku.com/articles/13849/understanding-four-isolation-levels-in-mysql