MySQL 与 PostgreSQL 的事务与并发差异
对比 MySQL InnoDB 与 PostgreSQL 在事务、MVCC、隔离级别、锁与恢复日志上的差异,帮助把相同术语还原到具体产品实现。
#type / synthesis
#status / growing
#tech / dev / backend
#resource / mysql
#resource / postgresql
[!info] related notes
MySQL 与 PostgreSQL 的事务与并发差异
范围
这篇聚焦 MySQL InnoDB 和 PostgreSQL 在事务落地、并发控制与恢复链路上的差异,不展开复制拓扑、高可用架构和运维参数细节。
为什么要放在一起理解
初学时最容易误以为:
- SQL 一样,事务行为就一样
- 都说支持 ACID 和 MVCC,所以差异只是语法层面
但在真实系统里,往往正是实现差异决定了这些现象:
- 为什么同一段业务代码在两个数据库上的默认行为不同
- 为什么一个数据库更容易出现范围锁等待,另一个更容易让你遇到序列化失败或版本可见性问题
- 为什么讨论日志时,有人说 WAL,有人说 Redo / Undo / Binlog
为什么这些差异会同时出现
事务并不是独立组件,它要同时协调:
- 版本可见性
- 锁冲突
- 提交与恢复
- 默认隔离级别
MySQL InnoDB 和 PostgreSQL 在这些层面的实现路线不同,所以即使表面上都叫“事务”“MVCC”“可重复读”,工程体验也会不一样。
依赖路径 / 调用链 / 演进链
可以从五个层面观察:
- 默认隔离级别
- MVCC 版本可见性实现
- 锁的粒度和范围保护策略
- 提交与恢复日志体系
- 死锁、冲突与错误表现
对比与易混淆点
| 维度 | MySQL InnoDB | PostgreSQL | 关注点 |
|---|---|---|---|
| 默认隔离级别 | 常见是 REPEATABLE READ | 常见是 READ COMMITTED | 同样业务在默认配置下看到的可见性可能不同 |
| MVCC 实现 | 常见通过 [[undo-log | Undo Log]] 等机制支撑旧版本 | 更直接依赖行版本与事务可见性信息 |
| 锁策略 | 范围更新时更容易出现 gap lock、next-key lock 一类现象 | 更常依赖行级冲突和快照可见性 | 范围查询和范围更新的阻塞感受不同 |
| 恢复与日志 | 会同时遇到 [[redo-log | Redo Log]]、[[undo-log | Undo Log]]、[[binlog |
| 冲突表现 | 更常见锁等待、死锁回滚等直观现象 | 在更强一致场景下也常见序列化失败或重试需求 | 应用层错误处理和重试策略可能不同 |
一个最常见的误区
很多人会说:
- MySQL 有锁,PostgreSQL 没那么锁
更准确的说法其实是:
- 两者都会锁
- 两者都支持 MVCC
- 只是它们在“何时更早加锁、范围如何保护、旧版本如何提供、冲突如何暴露”上做了不同实现选择
所以同一个业务在 MySQL 上可能更明显感受到范围锁,在 PostgreSQL 上可能更明显感受到快照语义、可见性和重试要求。
如何把它们和前面几篇概念页对应起来
- 想理解“事务承诺了什么” -> 先看 事务 和 ACID
- 想理解“并发时能看到什么” -> 看 事务隔离级别
- 想理解“为什么读写能少阻塞” -> 看 MVCC
- 想理解“为什么还会等待和死锁” -> 看 数据库锁
- 想理解“为什么提交后宕机还能恢复” -> 看 数据库日志
这篇的角色不是重复解释这些概念,而是告诉你:同样一组概念,在 MySQL 和 PostgreSQL 里落地方式并不完全一样。
边界与易混淆点
- 名称相同不代表实现相同,尤其是
REPEATABLE READ、MVCC 和日志体系。 - 不能把 PostgreSQL 的 WAL 简单等同于 MySQL 的某一个单独日志;它们的术语切分方式不同。
- “默认行为差不多”不代表边界场景差不多,范围更新、热点写入和长事务尤其容易暴露差异。