首先我们假设一个场景,数据库当前的事务,可以读不提交的数据,其实这也对应着mysql的RU(Read Uncommited 读取未提交)这么一种隔离级别,那会引发什么问题?
第1幕:RU隔离级别(读未提交)
假设银行数据库隔离级别是 RU(读未提交)
👨💻 用户A发起转账:
START TRANSACTION;
UPDATE 账户表 SET 余额 = 余额 - 1000 WHERE 用户 = 'A'; -- 还没提交!
👩💻 用户B此时查询余额:
SELECT 余额 FROM 账户表 WHERE 用户 = 'A'; -- 读到了A未提交的余额(脏读!)
⚠️ 问题:用户B读到了用户A未提交的数据,这就有问题了!!!
如果读到的数据在之后被回滚了,那么用户B读取到的就是无效的数据,也就是用户B得到了错误反馈的数据
---------------------------------------------------------------------------------------------------------------------------------
要解决它也很简单,既然是因为能够读未提交的数据,那我们就把标准提高,只能读已提交的数据,这也就对应着更高一级的隔离级别RC(Read Committed读已提交)
第2幕:RC隔离级别(读已提交)
此时银行把隔离级别提升到 RC(读已提交)
👨💻 用户A再次转账:
START TRANSACTION;
UPDATE 账户表 SET 余额 = 余额 - 1000 WHERE 用户 = 'A';
-- 还没提交!
👩💻 用户B查询余额:
SELECT 余额 FROM 账户表 WHERE 用户 = 'A'; -- 此时只能看到A的旧余额(不会脏读)
✅ 脏读解决!
👨💻 用户B的事务内两次读取:
START TRANSACTION;
SELECT 余额 FROM 账户表 WHERE 用户 = 'A'; -- 第一次读余额是1000
-- 此时A提交了转账:
COMMIT;--注意这是用户A的命令
SELECT 余额 FROM 账户表 WHERE 用户 = 'A'; -- 第二次读余额变成900(不可重复读!)
⚠️问题:同一事务内多次读取同一数据,结果不一致 → 不可重复读(其他事务提交的修改影响了当前事务的读取)。
那我们又该怎么解决这个问题呢?
答:那就再提隔离级别!
没错,我们再把隔离级别往上提:那这个隔离级别的名字该怎么取呢,诶!我们不是为了解决不可重复读问题吗,那就简单了,直接取名“可重复读”,没错哈,mysql官方也是这么取名的RR隔离级别也就是(Repeatable Read可重复读)。
第3幕:RR隔离级别(可重复读)
银行继续提升到 RR(可重复读)
👨💻 用户B的事务内两次读取:
START TRANSACTION;
SELECT 余额 FROM 账户表 WHERE 用户 = 'A'; -- 第一次读余额是1000
-- 此时A提交了转账:
COMMIT;
SELECT 余额 FROM 账户表 WHERE 用户 = 'A'; -- 第二次读还是1000(可重复读!)
✅ 不可重复读解决!
我们发现,此时不可重复读问题我们迎刃而解了,但接下来不出意外又会产生问题了...
没错!
👨💻 用户B想统计「余额>500的用户数量」:
START TRANSACTION;
SELECT COUNT(*) FROM 账户表 WHERE 余额 > 500; -- 第一次查是10人
-- 此时用户C新注册并存入600元,且提交:
COMMIT;
SELECT COUNT(*) FROM 账户表 WHERE 余额 > 500 FOR UPDATE; -- 当前读,结果为 11(幻读)
⚠️ 问题:同一事务内多次查询范围数据,结果集数量变化 → 幻读(其他事务新增或删除符合条件的数据)。
这么一看,有人会说了:你这幻读和不可重复读不是一样吗,都是用户第二次获得的结果和第一次不一样吗?
没错,确实不一样,但是请注意,不可重复读是对同一行数据被其他事务修改了(主要针对update操作),相当于你盯着某个具体的数据反复看,结果它变了,更侧重返回的具体结果信息的概念。而幻读其他事务新增或删除了符合你查询条件的数据(主要针对Insert/Delete操作),你统计某个范围的数据总量,结果发现“多出来”或“消失了”一些数据,也就是更侧重返回结果数量的概念。
相信到这我们已经可以分清这两者的区别,那这时候会有人说,我们该怎么解决幻读呢?
事实上幻读的一个比较简单的解决思路就是,串行化,也就是所有事务排队执行,彻底杜绝问题,但性能暴跌(相当于单线程操作数据库)。那有没有其他解决方案呢?
有的兄弟,有的!
这就要涉及间隙锁以及MVCC机制等东西了,本文主要目的是让大家理清隔离级别以及事务并行产生的一些问题,所以暂不介绍这些内容。
如果觉得博主讲的还算可以,希望大家点点赞和关注,你的支持就是小编最大的动力