Read Committed隔离级表述存疑?PostgreSQL文档矛盾点解析
Read Committed隔离级别下事务内SELECT结果的疑问解答
核心疑问
在PostgreSQL的Read Committed隔离级别下,单个事务内的两次SELECT会不会得到不同结果?官方文档的两个表述看似矛盾:
- 不带FOR UPDATE/SHARE子句的SELECT查询仅能看到查询开始前已提交的数据;绝不会看到未提交数据或查询执行期间并发事务提交的变更,实际上查询看到的是开始运行瞬间的数据库快照。但SELECT能看到自身事务中之前未提交的更新效果。
- 需注意,若其他事务在第一个SELECT开始后、第二个SELECT开始前提交变更,同一事务内的两次连续SELECT可能得到不同结果。
解答:两个表述的核心差异
这两个表述并不矛盾,关键要区分单条查询的快照生命周期和事务内多查询的快照生成规则:
- 表述1针对的是单条SELECT查询本身:一旦这条查询开始执行,就会生成一个固定的数据库快照,整个查询的执行过程(哪怕是关联多表的复杂查询)都会基于这个快照返回结果,不会读取到查询执行期间其他事务提交的新数据。
- 表述2针对的是事务内的多条SELECT查询:Read Committed隔离级别下,事务中的每一条SELECT都会独立生成新的快照——快照的时间点是这条SELECT开始执行的瞬间。如果两条SELECT之间有其他事务提交了数据变更,第二条SELECT的快照就会包含这些新提交的内容,自然会和第一条的结果产生差异。
直观例子
- 事务A启动,执行第一条
SELECT * FROM table,此时生成快照S1,返回S1时刻的表数据。 - 事务B完成一条数据插入并提交。
- 事务A执行第二条
SELECT * FROM table,此时生成快照S2(时间点在事务B提交之后),因此第二条查询会看到事务B插入的数据,结果和第一条不同。
而如果是一条耗时10秒的复杂SELECT(比如关联多张表、带聚合计算),哪怕执行到第5秒时事务B提交了数据,这条查询依然只会使用初始的S1快照,不会读取到事务B的变更。
内容的提问来源于stack exchange,提问作者ZiiMakc
相关产品推荐
相关产品推荐

