解读Mysql8中的事务隔离级别

事务的隔离级别与几个关键词有关: 脏数据,不可重复读,幻读,一致性读

假设有一个 accounts 表:

diff 复制代码
+----+---------+
| id | balance |
+----+---------+
|  1 | 1000.00 |
|  2 |  0.00 |
+----+---------+

READ UNCOMMITED (读未提交模式)

Shell A Shell B
set session transaction isolation level read uncommitted; set session transaction isolation level read uncommitted;
start transaction; start transaction;
select * from accounts where id=1; select * from accounts where id=1;
结果是: ` 1
update accounts set balance=balance+100 where id=1;
结果是: Query OK, 1 row affected (0.01 sec)
select * from accounts where id=1; select * from accounts where id=1;
结果是: ` 1
rollback
select * from accounts where id=1; select * from accounts where id=1;
结果是: ` 1

这个案例中, Shell B 执行 rollback 之前, Shell A 就读取到了 Shell B 存入的数据, 此时账户中的 100 就叫 脏数据, 如果 Shell B 在真实业务中执行了 rollback, 那此时 Shell A 中读取到的就是错误数据, 如果是在银行业务中出现了此类问题, 将会产生严重的后果

READ COMMITTED (读已提交模式)

Shell A Shell B
set session transaction isolation level read committed; set session transaction isolation level read committed;
start transaction; start transaction;
select * from accounts where id=1; select * from accounts where id=1;
结果是: ` 1
update accounts set balance=balance+100 where id=1;
结果是: Query OK, 1 row affected (0.01 sec)
select * from accounts where id=1; select * from accounts where id=1;
结果是: ` 1
commit;
select * from accounts where id=1; select * from accounts where id=1;
结果是: ` 1

这个模式中, 在 Shell B 的事务提交之前, Shell A 已经读取不到脏数据 了, 只有在 Shell B 提交后才能读取到 update 后的值

但是这还有一个问题: Shell A 在同一个事务中读取同一行的数据, 出现了不同的结果, 这是因为 Shell A 在执行事务期间, Shell B 的事务可以照常修改数据, 这种现象就叫 (Shell A)不可重复读

REPEATABLE READ (可重复读模式)

Shell A Shell B
set session transaction isolation level repeatable read; set session transaction isolation level repeatable read;
start transaction; start transaction;
select * from accounts where id=1; select * from accounts where id=1;
结果是: ` 1
update accounts set balance=balance+100 where id=1;
结果是: Query OK, 1 row affected (0.01 sec)
select * from accounts where id=1; select * from accounts where id=1;
结果是: ` 1
commit;
select * from accounts where id=1; select * from accounts where id=1;
结果是: ` 1

READ COMMITTED模式不同的是, 即便是 Shell B 中的提交了事务, Shell A 中查询出来的依然是1000的余额, 解决了 不可重复读 问题, 这是因为该模式下,一次性读 机制让事务中的每次 select 都返回事务中第一次select所建立的快照

另外, 在这个模式下, 即便其他事务对该事务所影响的行执行了删除操作, 在当前事务中, 依然能够看到被删除的数据

由于该模式还是允许其他事务修改数据, 所以可能出现一些非预期的情况, 下面这是官网的例子:

Shell A Shell B
set session transaction isolation level repeatable read; set session transaction isolation level repeatable read;
start transaction; start transaction;
select COUNT(c2) from t1 where c2 = 'abc';
结果: Returns 0: no rows match.
插入 10 条数据insert t1 values (...)
commit;
update t1 set c2 = 'cba' where c2 = 'abc';
select COUNT(c2) from t1 where c2 = 'cba';
结果: Returns 10

在这个例子中,Shell A 在 Shell B 提交后执行了update语句, 导致把 Shell B 提交的数据也更新了, 这个现象就叫做 幻读(Shell A 更新了事务开始时不存在的数据), 在实际开发中也是很危险的行为

SERIALIZABLE (串行模式)

Shell A Shell B
set session transaction isolation level serializable; set session transaction isolation level serializable;
start transaction; start transaction;
select count(id) from accounts';
结果: Returns 2
插入 1 条数据insert accounts values (...)
暂停执行, 等待 Shell A 提交
commit; 自动执行 insert 语句

从过程中可以看到, Shell B 中的 insert 语句被暂停执行了, 这是啥因为 serializable 模式下, 所有普通的select语句都被隐式添加了for share的共享锁: 当前事务开启后, 其他事务只能读取被锁定的行, 不能修改; 这个案例中由于执行了count()函数, 相当于是该表整个被锁定了, 所以 Shell B 也无法执行 insert语句

这个模式就解决了幻读的问题

一致性读(consistent read)

一致性读 是 InnoDB 在 READ COMMITTEDREPEATABLE READ 隔离级别下处理 select 语句的默认模式。一致性读不会对其访问的表设置任何锁,因此在对表执行一致性读的同时,其他会话可以自由地修改这些表。

READ COMMITTED模式下, 一致性读 保证事务中每次 select 都会读取并设置其自己的最新快照

而在REPEATABLE READ模式下, 一致性读 保证事务中每次 select 的结果都是相同的, 这是因为该模式下, 当发出一致读取(即普通的 SELECT 语句)时,InnoDB 会为所在事务提供一个时间点,后续事务内的查询将根据该时间点查看数据库

相关推荐
唐青枫10 小时前
MySQL EXISTS 详解:存在性判断、NOT EXISTS 与实战示例
sql·mysql
2301_7736436212 小时前
华为云存储实验
网络·mysql·华为云
quan263113 小时前
20260529,日常开发-数据库主从问题
java·mysql·主从·延迟
DIY源码阁16 小时前
JavaSwing宿舍管理系统 - MySQL版
java·数据库·mysql·eclipse
cfm_291416 小时前
MySQL8.0 InnoDB Cluster
数据库·mysql
夜微凉418 小时前
三、MySQL
android·数据库·mysql
暴躁小师兄数据学院18 小时前
【AI大数据工程师特训笔记】第11讲:正则表达式与正则函数
数据库·mysql
IT龟苓膏19 小时前
MySQL InnoDB 内存结构与性能调优:Buffer Pool、脏页、刷盘、临时表和 filesort 一篇讲清
数据库·mysql
加号319 小时前
【MySQL】 审计功能深度解析:从原理到落地实践
数据库·mysql
还是鼠鼠19 小时前
AI掘金头条新闻系统 (Toutiao News)-获取用户信息
后端·python·mysql·fastapi·web