PostgreSQL中READ COMMITTED级别的只读事务异常是什么及如何复现?
只读事务异常(read-only transaction anomaly)解析与复现
1. 什么是只读事务异常?
只读事务异常指的是:一个只读事务在执行过程中,多次读取到的数据组合,无法对应数据库在任何一个时间点的一致状态。
简单来说,这个只读事务看到的不是数据库某一时刻的完整快照,而是不同时间点数据的“拼接”——比如先读取了表A的旧状态,之后又读取了表B被其他事务修改后的新状态,这两组数据放在一起,在数据库的历史中从未同时存在过,违背了“读取一致性”的直觉。
2. PostgreSQL READ COMMITTED级别下的复现步骤
前置准备
先创建测试表并插入初始数据:
CREATE TABLE accounts (id INT PRIMARY KEY, balance INT); INSERT INTO accounts VALUES (1, 100), (2, 100);
复现操作(需要3个独立的SQL会话/窗口)
会话1(只读事务):
-- 启动READ COMMITTED级别的事务 BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; -- 第一次读取:获取账户1的余额 SELECT balance FROM accounts WHERE id = 1; -- 此时返回结果为100会话2(修改事务):
BEGIN; -- 执行转账操作:从账户1转50到账户2 UPDATE accounts SET balance = balance - 50 WHERE id = 1; UPDATE accounts SET balance = balance + 50 WHERE id = 2; -- 提交事务,让修改生效 COMMIT;回到会话1:
-- 第二次读取:获取账户2的余额 SELECT balance FROM accounts WHERE id = 2; -- 此时返回结果为150
异常验证
会话1的只读事务先后得到了账户1=100和账户2=150的结果,但数据库从未存在过这样的状态:
- 转账前状态:
(100, 100) - 转账后状态:
(50, 150)
这两组数据的组合完全不符合任何时间点的一致性,也就触发了只读事务异常。
内容的提问来源于stack exchange,提问作者Super Kai - Kazuya Ito
相关产品推荐
相关产品推荐

