文章目录
- 一、四个隔离级别举例说明
- 1. Read Uncommitted:可以看到别人尚未提交的修改
- 2. Read Committed:只能看到已经提交的数据
- 3. Repeatable Read:同一事务重复读取通常保持一致
- 标准定义下仍可能出现幻读
- 4. Serializable:效果如同事务一个接一个执行
- 四个级别对照
- 二、Repeatable Read 和 Read Committed 作为常见默认值
- 有时候“重复看到旧值”为什么反而合理?
- 它不会永远看到旧值
- 大多数单条 SQL 感觉不到这个区别
- MySQL 为什么选择 Repeatable Read?
- 想读取最新数据怎么办?
- 方法一:结束当前事务
- 方法二:使用 Read Committed
- 方法三:读取并准备修改时加锁
- Repeatable Read 也不是万无一失
- 最后的理解
一、四个隔离级别举例说明
可以把四个隔离级别理解为:
当两个事务同时操作数据库时,一个事务能看到另一个事务进行到哪一步。
隔离能力从弱到强:
Read Uncommitted ↓ Read Committed ↓ Repeatable Read ↓ Serializable代价通常是:隔离越强,并发限制越多,也越可能发生等待或事务重试。
1. Read Uncommitted:可以看到别人尚未提交的修改
初始余额:
Alice 余额 = 100事务 A 扣款,但还没有提交:
BEGIN;UPDATEaccountsSETbalance=0WHEREname='Alice';-- 尚未 COMMIT事务 B 此时查询:
SELECTbalanceFROMaccountsWHEREname='Alice';可能看到:
0随后事务 A 发生错误并回滚:
ROLLBACK;数据库实际余额重新变成:
100事务 B 刚才读取的0是一个从未真正生效的数据,这叫脏读:
事务 A:100 ──修改为 0──> 最后回滚为 100 ↑ 事务 B: 读到了 0类比:
你看到了别人还没提交的草稿,但对方最后把草稿删掉了。
2. Read Committed:只能看到已经提交的数据
初始商品价格:
价格 = 100事务 A 第一次读取:
BEGIN;SELECTpriceFROMproductsWHEREid=1;结果:
100然后事务 B 修改价格并提交:
BEGIN;UPDATEproductsSETprice=120WHEREid=1;COMMIT;事务 A 再次读取同一行:
SELECTpriceFROMproductsWHEREid=1;这次结果可能是:
120同一个事务里,两次读取同一行,结果不同:
事务 A 第一次读:100 事务 B 修改提交:120 事务 A 第二次读:120这叫不可重复读。
Read Committed 避免了脏读,因为只有事务 B 提交后,事务 A 才能看到120。但它不保证同一个事务中的多次查询结果一致。
类比:
你只能看到别人正式发布的内容,但你刷新页面后,内容可能已经变了。
3. Repeatable Read:同一事务重复读取通常保持一致
还是刚才的价格:
价格 = 100事务 A 第一次读取:
BEGIN;SELECTpriceFROMproductsWHEREid=1;