ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

WHAT - 数据库 db 事务的四个隔离级别

WHAT - 数据库 db 事务的四个隔离级别

文章目录

  • 一、四个隔离级别举例说明
    • 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;
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进