知识卡片
四种隔离级别的强弱本质是锁的持有时长而非固有属性
内容
幻读、不可重复读、脏读常被当作数据库四个隔离级别各自”固有”的特征来死记 硬背,但它们其实都是同一套[[写锁读锁范围锁与两阶段锁如何实现串行化隔离]] 在不同持有时长组合下产生的表面现象。可串行化对读写数据都加锁并一直持有 到事务结束,还额外加范围锁禁止插入,因而完全隔离;可重复读只比它少了 范围锁,所以两次相同的范围查询可能因为别的事务插入了新数据而得到不同 结果(幻读);读已提交的写锁仍持续到事务结束,但读锁在查询完成后就立刻 释放,所以同一行数据两次查询之间若被别的事务改过并提交,会读到不同结果 (不可重复读);读未提交只加写锁完全不加读锁,因此能读到别的事务尚未 提交、随时可能回滚的数据(脏读)。理解”现象由锁的组合产生”而非死记概念, 就能推出一个关键结论:具体数据库的实现可能与理论有出入,例如MySQL/InnoDB 默认的可重复读,在只读事务中借助MVCC能完全避免幻读,但读写事务里仍会 出现——因为它此时走的是加锁读而非快照读。
结构图:
flowchart LR
S["可串行化<br/>读锁+写锁+范围锁, 全程持有"] -->|去掉范围锁| RR["可重复读<br/>读锁+写锁, 全程持有<br/>可能幻读"]
RR -->|读锁提前释放| RC["读已提交<br/>仅写锁全程持有<br/>可能不可重复读"]
RC -->|完全不加读锁| RU["读未提交<br/>仅写锁<br/>可能脏读"]
参考来源
- 位置:《凤凰架构:构建可靠的大型分布式系统》第3章"事务处理"3.1.2节
"实现隔离性"(源文件:_epub-src对应OEBPS/Text/chapter27.xhtml)
- 结论依据:原文逐级说明可重复读比可串行化少了范围锁导致幻读、读已提交
的读锁提前释放导致不可重复读、读未提交完全不加读锁导致脏读,并明确
指出"不同隔离级别以及幻读、不可重复读、脏读等问题都只是表面现象,是
各种锁在不同加锁时间上组合应用所产生的结果",直接支撑本卡片结论。
- 原始内容:其实不同隔离级别以及幻读、不可重复读、脏读等问题都只是表面
现象,是各种锁在不同加锁时间上组合应用所产生的结果,以锁为手段来实现
隔离性才是数据库表现出不同隔离级别的根本原因。