别的数据库默认 RC,为什么 MySQL 默认 RR
Oracle、PostgreSQL、SQL Server 默认都是读已提交(RC),只有 MySQL 默认可重复读(RR)。原因是历史包袱。
早年 binlog 只有 STATEMENT 格式,从库按提交顺序重放 SQL 原文。来看 RC 下会出什么事,表里有 id = 1 和 10:
A: DELETE FROM t WHERE id < 10; -- 不提交
B: INSERT INTO t VALUES (5); -- RC 不锁间隙,插得进去,B 先提交
A: COMMIT;- 主库:A 删除时 5 还不存在,所以 5 留下了。
- binlog 按提交顺序是「先 INSERT、后 DELETE」,从库重放会把 5 删掉。
主从不一致了。RR 的间隙锁让 B 必须等 A 提交,执行顺序就和提交顺序一致了。
如今 binlog 默认是 ROW 格式(记每行改前改后的样子),这个理由已经不成立,所以不少公司改成 RC + ROW。RR 也不是 RC 的升级版:多了防幻读,代价是更多锁冲突和死锁。