必须显式指定ResultSet.TYPE_FORWARD_ONLY和ResultSet.CONCUR_READ_ONLY两个参数,否则驱动可能默认启用缓存型游标导致数据截断、内存溢出或遍历异常;推荐配合setFetchSize(1000–5000)实现流式读取。

Java JDBC 中设置查询游标类型和并发方式,关键是在创建 PreparedStatement 或 Statement 时**显式传入两个参数**:结果集类型(ResultSet type)和并发模式(ResultSet concurrency)。不传或传错,容易导致数据丢失、内存溢出或遍历异常。
必须指定的两个核心参数
创建语句对象时,需明确指定:
-
游标类型:推荐
ResultSet.TYPE_FORWARD_ONLY—— 只允许从前往后单次遍历,轻量、流式、低内存占用,适用于绝大多数导出、分页、大数据读取场景。 -
并发模式:推荐
ResultSet.CONCUR_READ_ONLY—— 结果集只读,禁止通过updateXXX()修改数据,避免驱动启用额外锁机制或缓存逻辑。
示例代码:
String sql = "SELECT id, name, amount FROM orders WHERE status = ?";
PreparedStatement pstmt = connection.prepareStatement(
sql,
ResultSet.TYPE_FORWARD_ONLY, // 游标类型
ResultSet.CONCUR_READ_ONLY // 并发模式
);
pstmt.setString(1, "done");
ResultSet rs = pstmt.executeQuery();
为什么不能省略这两个参数
若使用无参 prepareStatement(sql),JDBC 驱动可能按默认策略选择游标类型(如 TYPE_SCROLL_INSENSITIVE),这会触发客户端全量缓存行为。尤其在 GBase 8a、MySQL 或某些 Oracle 驱动中,会导致:
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 结果集被截断(例如 limit 1000 实际只返回 700 条);
- 内存暴涨甚至 OOM(百万级结果全加载进 JVM);
- rs.next() 提前返回 false,看似“没数据”,实为丢行。
显式声明 TYPE_FORWARD_ONLY + CONCUR_READ_ONLY 是告诉驱动:“我只要顺序读,不回滚、不修改”,从而启用服务器端游标或流式拉取机制。
配合 fetchSize 提升流式效率
仅设游标类型还不够,建议同步设置 fetch size,让驱动按批从数据库拉取数据(而非一次全取或一行一行取):
pstmt.setFetchSize(2000); // 建议值:1000–5000,根据网络延迟与单行大小调整
- 太小(如 10):频繁网络往返,性能差;
- 太大(如 100000):客户端内存压力大,且部分驱动有上限限制;
- GBase 8a 和 MySQL Connector/J 推荐 1000–5000;SQL Server 驱动对
TYPE_FORWARD_ONLY下该值更敏感,宜设为 500–2000。
其他常见组合说明(慎用)
以下组合虽合法,但多数生产场景不推荐:
-
TYPE_SCROLL_INSENSITIVE + CONCUR_READ_ONLY:支持first()、last()、absolute(n),但需缓存全部结果,易 OOM; -
TYPE_SCROLL_SENSITIVE + CONCUR_UPDATABLE:可动态感知其他事务变更并更新当前行,但性能最差、锁开销高,仅限特殊实时校验场景; -
CONCUR_UPDATABLE单独使用需配合主键,且数据库表必须有唯一索引,否则执行rs.updateRow()会报错。
日常查询、导出、ETL 等任务,坚持用 FORWARD_ONLY + READ_ONLY 最稳妥。

















