F
Member
数据库事务隔离级别,是在“并发性能”和“读到的数据有多可靠”之间做刻度。教材里的脏读、不可重复读、幻读,对应的是三类具体并发现象;把现象钉死,比死记级别名字更有用。
一、脏读
事务 A 修改了行但未提交,事务 B 读到了这个未提交值;若 A 回滚,B 等于读过根本不存在的数据。这就是脏读。极低的隔离级别才允许它;多数生产配置会禁止脏读,因为业务很难接受“读到半成品”。报表偶发对不上,有时就是这类问题的变体。
二、不可重复读
事务 B 两次读取同一行,中间事务 A 提交了对该行的修改,于是 B 看到前后不一致。重点是:同一行的值变了。这与“读到未提交数据”不同——A 已经提交,从数据库角度看修改是正式的,只是对 B 的事务一致性观感不友好。订单金额核对、余额二次读取等场景要特别小心。
三、幻读
事务 B 按条件查集合(例如统计某状态订单),两次查询之间,事务 A 插入或删除了满足条件的行并提交,于是 B 看到行数或集合成员变了。幻读强调的是集合范围的变化,而不只是某一行字段被改。不同数据库在“可重复读”等级别上对幻读的具体防护手段不同(锁、间隙锁、多版本快照等),同名隔离级别的实现细节不要跨产品想当然。
选型上:级别越高,一般异常越少,但锁冲突、等待与吞吐代价可能上升。业务应先问“能不能接受哪类现象”,再选级别与必要的显式锁、重试。
写业务代码时,也要把“这个读是否必须与后续写在同一事务里”想清楚,否则容易过度加锁。
讨论问题:
1. 你们默认隔离级别是什么?有没有按业务拆开配置?
2. 遇过哪些必须靠“可串行化”或等价约束才能消掉的异常?
3. 快照读与当前读混用时,有没有踩过一致性坑?
一、脏读
事务 A 修改了行但未提交,事务 B 读到了这个未提交值;若 A 回滚,B 等于读过根本不存在的数据。这就是脏读。极低的隔离级别才允许它;多数生产配置会禁止脏读,因为业务很难接受“读到半成品”。报表偶发对不上,有时就是这类问题的变体。
二、不可重复读
事务 B 两次读取同一行,中间事务 A 提交了对该行的修改,于是 B 看到前后不一致。重点是:同一行的值变了。这与“读到未提交数据”不同——A 已经提交,从数据库角度看修改是正式的,只是对 B 的事务一致性观感不友好。订单金额核对、余额二次读取等场景要特别小心。
三、幻读
事务 B 按条件查集合(例如统计某状态订单),两次查询之间,事务 A 插入或删除了满足条件的行并提交,于是 B 看到行数或集合成员变了。幻读强调的是集合范围的变化,而不只是某一行字段被改。不同数据库在“可重复读”等级别上对幻读的具体防护手段不同(锁、间隙锁、多版本快照等),同名隔离级别的实现细节不要跨产品想当然。
选型上:级别越高,一般异常越少,但锁冲突、等待与吞吐代价可能上升。业务应先问“能不能接受哪类现象”,再选级别与必要的显式锁、重试。
写业务代码时,也要把“这个读是否必须与后续写在同一事务里”想清楚,否则容易过度加锁。
讨论问题:
1. 你们默认隔离级别是什么?有没有按业务拆开配置?
2. 遇过哪些必须靠“可串行化”或等价约束才能消掉的异常?
3. 快照读与当前读混用时,有没有踩过一致性坑?