PostgreSQL JDBC单表扫描ResultSet行数为预期4倍的问题
排查Tomcat JDBC连接池返回ResultSet行数异常的问题
这种明明数据库里只有3行数据,代码里却拿到4倍结果的情况确实挺闹心的,我帮你梳理几个常见的排查方向和解决办法:
先确认核心信息是否一致
- 把代码里执行的完整SQL语句打印出来,和你在pgAdmin里跑的做对比,确保没有差异——比如会不会代码里不小心写了重复的表关联(比如
SELECT * FROM ref_table t1, ref_table t2),或者拼接SQL时多了循环导致重复? - 在遍历ResultSet的时候加个日志,打印每行的唯一标识(比如主键),看看是每行重复了4次,还是真的出现了额外的行——这能帮你定位是重复执行了查询,还是结果集本身有问题。
检查代码里的ResultSet处理逻辑
大概率是这里出了问题:
- 有没有不小心在循环里重复添加元素?比如是不是写了嵌套循环,或者在
rs.next()的循环里多次调用list.add()? - 有没有重复执行查询语句?比如是不是在一个4次的循环里反复调用了
executeQuery(),导致每次查询的3行都被加到列表里,最后凑成12行? - 之前用
putIfAbsent能规避,说明返回的是重复数据,这更指向代码里重复获取了结果,或者连接池的配置导致重复执行。
排查Tomcat JDBC连接池的配置
打开你的context.xml(或者数据源配置文件),检查这几个关键参数:
defaultAutoCommit:如果设置为false,有没有在执行查询后手动提交?虽然查询一般不需要提交,但如果同一个连接被重复使用且没有重置,可能会出现异常;建议设置为true(默认值也是true)。testOnBorrow和validationQuery:如果配置了验证查询,会不会验证的结果和业务查询的结果混在了一起?不过这个概率比较低,但可以暂时把testOnBorrow设为false测试一下。- 连接池的
maxIdle、minIdle这些参数一般不会导致这个问题,但可以确认下有没有配置错误导致连接复用异常。
检查PostgreSQL驱动兼容性
Tomcat 9.0搭配PostgreSQL 10.2,要确保驱动版本是兼容的:
- 建议使用PostgreSQL JDBC Driver 42.2.x系列(适配PostgreSQL 9.4到12),如果用的是太老的驱动(比如9.x系列),可能和Tomcat的连接池存在兼容性问题,导致ResultSet处理异常。
- 替换驱动后再测试,看看问题是否消失。
做个最小化测试
写个简单的测试代码,绕过Tomcat连接池,直接用JDBC原生连接执行查询:
public static void main(String[] args) throws Exception { Class.forName("org.postgresql.Driver"); Connection conn = DriverManager.getConnection("jdbc:postgresql://localhost:5432/yourdb", "user", "pass"); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("SELECT * FROM your_ref_table"); int count = 0; while (rs.next()) { count++; System.out.println("Row " + count + ": " + rs.getString("your_unique_col")); } System.out.println("Total rows: " + count); rs.close(); stmt.close(); conn.close(); }
如果这个测试里行数正常(3行),那问题肯定出在Tomcat连接池的配置或者代码里的连接使用逻辑;如果还是异常,那就要检查数据库本身或者SQL的问题了。
内容的提问来源于stack exchange,提问作者dtgman




