事务隔离级别本质差异(从“读”到“写”的一次性搞懂)
----------------------------------------------------------------------------------------------
一、为什么「只看 SELECT」一定会把你带沟里?
很多人(包括你刚才)卡在一句话上:
PG RC:每次 SELECT 都重新拍照
那不是和 MySQL RC 一样吗?
这句话在“读”层面是对的,但事务隔离的核心不在读,而在写。
👉 真正决定数据正确性的,是 UPDATE / DELETE 的语义。
----------------------------------------------------------------------------------------------------------------------------
二、必须先建立的一个统一认知
所有主流数据库都遵循一个铁律:
UPDATE 一定是改“当前数据库中的某一行版本
区别只在于:
- 你能不能更新一个「你没真正见过的版本」
----------------------------------------------------------------------------------------------------------------------------
三、MySQL InnoDB 的核心模型(RR)
关键词
- 一致性视图(Read View)
- 当前读(Current Read)
- 锁兜底
---------------------------------------------------------------------------------------------------------
1️⃣ MySQL RR 是怎么读的?
START TRANSACTION;
SELECT balance FROM account WHERE id = 1;
- 生成一个 Read View
- 事务期间:
- 普通 SELECT 永远读 同一个快照
- ✅ 解决不可重复读
---------------------------------------------------------------------------------------------------------
2️⃣ MySQL RR 是怎么写的?(重点)
UPDATE account SET balance = balance - 50 WHERE id = 1;
⚠️ 这里会自动发生一件事:
- mysql 无视你的 Read View
- 强制读取 当前最新版本
- 然后基于最新版本计算并更新
📌 结论(非常重要)
MySQL RR:写 ≠ 你看到的那一版
---------------------------------------------------------------------------------------------------------------------------------
3️⃣ 这意味着什么?
```sql
你看到:balance = 100
真实当前:balance = 70
你更新后:balance = 20(成功)
```
- 数据库不会告诉你:
- 你刚才的判断基础已经过期了
- 所以
- 逻辑一致性靠你自己兜
- version 字段 / for update / 业务校验
---------------------------------------------------------------------------------------------------------------------------------
4️⃣ MySQL RR 到底解决了什么?
✅ 解决:
- 不可重复读
-
大部分幻读(Next-Key Lock)
❌ 没解决:
-
基于旧读进行写导致的业务错误
---------------------------------------------------------------------------------------------------------------------------------
四、PostgreSQL RC(为什么像 MySQL RR)
关键词
-
MVCC
-
Statement Snapshot
---------------------------------------------------------------------------------------------------------------------------------
1️⃣ PG RC 是怎么读的?
UPDATE account SET balance = balance - 50 WHERE id = 1;
-
UPDATE 会:
-
找当前可见的最新版本
-
基于它更新
-
📌 效果上:
PG RC ≈ MySQL RR
---------------------------------------------------------------------------------------------------------------------------------
3️⃣ 但注意
PG RC 仍然是:
-
读:不稳定
-
写:不校验你“是否基于旧认知”
👉 只是“碰巧行为像”,不是理念一样
---------------------------------------------------------------------------------------------------------------------------------
五、PostgreSQL RR(真正的分水岭)
关键词
-
Transaction Snapshot
-
MVCC 版本校验
-
写一致性
---------------------------------------------------------------------------------------------------------------------------------
1️⃣ PG RR 是怎么读的?
START TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SELECT balance FROM account WHERE id = 1;
PG 会做一件 MySQL 永远不会做的事:
校验:你要更新的这一行,还是不是你当初看到的版本?
3️⃣ 如果版本变了,会发生什么?
你看到:version = v1(balance=100)
当前真实:version = v2(balance=70)
结果:
-
❌ UPDATE 不会悄悄成功
-
❌ 不会帮你“自动算最新值”
-
✅ 更新 0 行 或 serialization failure
📌 PG RR 的核心语义:
你只能修改你真正“见过”的世界
---------------------------------------------------------------------------------------------------------------------------------
六、你问的那句关键理解,正式定稿
❓「PG RR 更新不需要加 version 判断了?」
✅ 结论:可以这样理解
但完整表述是:
PG RR 在数据库层,已经帮你做了版本一致性校验
等价于你在 MySQL 里手写的:
UPDATE account
SET balance = balance - 50
WHERE id = 1 AND version = ?
七、Serializable 是在干嘛?
一句话:
Serializable = 把“可能并发错误的执行”,直接拒绝掉
-
不让你写错
-
不帮你修错
-
让你重试
👉 PG 的 Serializable = 最强写正确性保障
---------------------------------------------------------------------------------------------------------------------------------
八、一句话对照表(终极记忆版)
| 数据库 | 隔离级别 | 本质 |
|---|---|---|
| MySQL | RR | 读你看到的,写最新的 |
| PG | RC | 读最新的,写最新的 |
| PG | RR | 只能写你见过的 |
| PG | Serializable | 并发不对就重来 |
九、什么时候差异会真的“坑你”?
👉 所有「先读 → 再算 → 再写」的业务
比如:
-
扣余额
-
发放额度
-
库存扣减
-
状态流转(NEW → PAYED → DONE)
MySQL RR:
-
你不加锁 / version,就可能“逻辑上错但数据库不报错”
PG RR:
-
数据库会直接告诉你:
“兄弟,你这次判断已经过期了”

965

被折叠的 条评论
为什么被折叠?



