知识卡片

MVCC用版本号实现读取时无锁的隔离优化

普通读书笔记卡

内容

[[四种隔离级别的强弱本质是锁的持有时长而非固有属性]]里的幻读/不可重复读/ 脏读,共同根源是”一个事务读、另一个事务写”互相干扰。多版本并发控制 (MVCC)针对这个特定场景做无锁优化:任何修改都不覆盖旧数据,而是产生 一个新版本与旧版本共存。可以把每行数据想象成带有两个隐藏字段 CREATE_VERSION和DELETE_VERSION,值是全局递增的事务ID;插入只写 CREATE_VERSION,删除只写DELETE_VERSION,修改则等价于”删旧插新”,同时 写两条记录各自的版本号。读取时根据隔离级别决定看哪个版本:可重复读固定 读取本事务开始时CREATE_VERSION小于等于自身事务ID的最新版本(保证同一 事务内两次读结果一致);读已提交则每次都取最新已提交版本。读未提交和 可串行化都用不上MVCC——前者直接读原始数据不需要版本概念,后者本来就 要阻塞其他事务的读取,与”无锁优化”的目标矛盾。MVCC只优化”读+写”场景, “写+写”的并发冲突仍要靠加锁解决,此时选乐观锁还是悲观锁完全取决于实际 竞争激烈程度,竞争激烈时乐观锁反而更慢,没有哪种天生更优。

参考来源

- 位置:《凤凰架构:构建可靠的大型分布式系统》第3章"事务处理"3.1.2节 "实现隔离性"(源文件:_epub-src对应OEBPS/Text/chapter27.xhtml) - 结论依据:原文定义CREATE_VERSION/DELETE_VERSION字段的写入规则,说明 不同隔离级别下MVCC的读取取舍策略,并指出MVCC只针对读写场景优化、写写 冲突仍需加锁,直接支撑本卡片结论。 - 原始内容:MVCC的基本思路是对数据库的任何修改都不会直接覆盖之前的数据, 而是产生一个新版本与老版本共存,以此达到读取时可以完全不加锁的目的…… 隔离级别是可重复读:总是读取CREATE_VERSION小于或等于当前事务ID的记录…… 隔离级别是读已提交:总是取最新的版本即可。