能,READ UNCOMMITTED 可读未提交数据,产生脏读;MySQL 不支持,PostgreSQL 需显式设置;READ COMMITTED 用语句级快照防脏读但有不可重复读;REPEATABLE READ 用事务级快照保证一致性,MySQL 用间隙锁防幻读;SERIALIZABLE 靠锁或SSI模拟串行,性能开销大。

READ UNCOMMITTED 能读到别人还没提交的数据吗?
能,而且正是它最典型的行为。这个级别下,SELECT 不加任何锁,也不检查事务是否已提交,所以会读到 UNCOMMITTED 的“脏数据”。比如事务 A 插入一行但没 COMMIT,事务 B 在此期间执行 SELECT 就可能看到这行——如果 A 后续 ROLLBACK,B 读到的就是根本不存在的数据。
- 实际中极少使用,仅在日志分析、监控类场景中容忍脏读时考虑
- MySQL 默认不支持该级别(InnoDB 强制升级为
READ COMMITTED) - PostgreSQL 支持,但需显式设置:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
READ COMMITTED 怎么避免脏读但还会出现不可重复读?
它通过“语句级快照”实现:每次 SELECT 都基于当前已提交的最新数据生成快照。所以第一次 SELECT 看不到未提交数据(解决脏读),但第二次 SELECT 可能因其他事务已提交而看到新值(导致不可重复读)。
- MySQL InnoDB 中,
READ COMMITTED下普通SELECT是快照读,但UPDATE/DELETE会加行锁并读最新提交版本 - PostgreSQL 行为类似,但快照在事务首次查询时建立,后续语句复用(注意:这点和 MySQL 不同)
- 常见坑:应用逻辑假设两次读结果一致(如“检查余额→扣款”,中间余额被他人改掉),此时必须升级隔离级别或加
SELECT ... FOR UPDATE
REPEATABLE READ 如何保证同一事务内多次读一致?
它用“事务级快照”:事务启动时拍一次全局快照,整个事务都基于这个快照读数据。因此不会出现不可重复读——哪怕其他事务已提交修改,本事务仍看不到。
- MySQL InnoDB 的
REPEATABLE READ还通过间隙锁(Gap Lock)防止幻读(但不是完全杜绝,比如新插入的记录在INSERT ... SELECT场景下仍可能引发幻象) - PostgreSQL 的
REPEATABLE READ实现的是真正的串行化快照(SSI),能避免大部分幻读,但不是靠锁,而是冲突检测后回滚 - 注意:MySQL 中
SELECT ... FOR UPDATE或SELECT ... LOCK IN SHARE MODE会读最新已提交数据,并加锁,不走快照,这是容易混淆的关键点
SERIALIZABLE 是真串行还是伪串行?
在大多数主流数据库里,它是靠锁模拟串行,不是真正排队执行。MySQL InnoDB 会将所有普通 SELECT 自动转成 SELECT ... LOCK IN SHARE MODE;PostgreSQL 则启用可串行化快照隔离(SSI),在提交时检测写偏移(write skew),冲突则回滚。
- 性能开销明显高于其他级别,尤其高并发读写混合场景
- 并非绝对无异常:比如两个事务同时读取同一行、各自计算后写入不同字段,在 SSI 下可能仍发生写偏移(需业务层额外校验)
- 如果你遇到死锁频发、响应延迟突增,先查是否误设了
SERIALIZABLE,再评估是否真需要它——多数一致性问题用REPEATABLE READ+ 显式锁更可控
实际选型时,别只盯着理论定义。MySQL 和 PostgreSQL 对同一名称级别的实现差异很大,甚至同一引擎在不同版本中行为也在变。看文档不如看 SHOW VARIABLES LIKE 'transaction_isolation' 和实际 EXPLAIN 锁信息来得实在。










