Postgres JDBC fetch size实现原理及事务数据可见性疑问
问题解答
核心原因:事务快照的一致性
你的判断完全正确——整个查询在单个事务中执行是看不到后续数据更新的根本原因,和fetchSize=1的流式查询机制无关。
Postgres的MVCC快照机制
Postgres基于MVCC(多版本并发控制)实现事务隔离,当你在事务中执行SELECT语句的瞬间,Postgres会为当前事务生成一个数据快照:
- 这个快照固定了事务能访问的数据状态,仅包含快照生成前所有已提交事务的修改
- 快照生成后,其他事务提交的任何数据更新,在当前事务结束前都不会被该事务看到
- 哪怕你设置了
fetchSize=1开启流式传输,也只是改变了数据从Postgres到客户端的传输批次(每次传1条),结果集的内容依然是基于快照生成的,不会每次rs.next()都重新去数据库拉取最新数据
关于fetchSize的误解纠正
你之前以为fetchSize是通过LIMIT+OFFSET实现的,但Postgres JDBC的流式查询逻辑是:
- 执行
SELECT时,Postgres已经确定了符合条件的结果集(基于快照) - 流式查询只是让客户端分批从Postgres的结果集中拉取数据,而不是每次
rs.next()都重新执行查询 - 所以即使中途有数据更新,也不会被加入到当前的结果集中
大查询的适用情况
不管是小查询还是SELECT * FROM table这类全表大查询,只要是在单个事务内执行的SELECT,都会遵循上述快照规则:事务开始后的数据变更不会出现在结果集里。
如何获取实时更新数据
如果需要在导入过程中看到后续的实时更新,可以将查询拆分为多个独立的小事务:
- 每次只查询一个
cursor范围的数据(比如WHERE cursor > ? AND cursor <= ?) - 处理完该批次后提交事务,再开启新事务查询下一个范围
- 每个新事务的快照都是最新的,就能获取到之前提交的所有更新
内容的提问来源于stack exchange,提问作者Dev K
相关产品推荐
相关产品推荐

