能否这样比较ResultSet?遇只读结果集deleteRow SQL异常
解决ResultSet比较时的
deleteRow错误问题 首先,咱们先搞清楚你遇到的错误根源:默认情况下,JDBC的ResultSet是只读且仅向前遍历的,它不支持deleteRow()这类更新操作——这就是你抛出java.sql.SQLException: Invalid operation for read only resultset: deleteRow的原因。而且直接在ResultSet上做跨库记录的比较和修改,本身也不是高效或合理的做法。
下面给你两种可行的解决方案,从简单到高效:
方案一:把ResultSet转成内存集合后再比较
这是最直观的做法,先把两个ResultSet的数据加载到内存中的集合(比如自定义实体类列表、Map列表),再在内存中做差异对比,避免直接操作ResultSet:
步骤1:封装ResultSet转集合的工具方法
private List<Map<String, Object>> resultSetToList(ResultSet rs) throws SQLException { List<Map<String, Object>> list = new ArrayList<>(); ResultSetMetaData metaData = rs.getMetaData(); int columnCount = metaData.getColumnCount(); while (rs.next()) { Map<String, Object> row = new HashMap<>(); for (int i = 1; i <= columnCount; i++) { row.put(metaData.getColumnName(i), rs.getObject(i)); } list.add(row); } return list; }
步骤2:加载两个结果集并找出差异
假设你用主键(比如id字段)来判断记录是否存在:
// 加载两个ResultSet到内存集合 List<Map<String, Object>> table1List = resultSetToList(table1ResultSet); List<Map<String, Object>> table2List = resultSetToList(table2ResultSet); // 先把table2的主键存到Set里,方便快速查找 Set<Object> table2Ids = table2List.stream() .map(row -> row.get("id")) .collect(Collectors.toSet()); // 找出table1中不在table2里的记录 List<Map<String, Object>> diffRecords = table1List.stream() .filter(row -> !table2Ids.contains(row.get("id"))) .collect(Collectors.toList());
步骤3:后续操作(如果需要修改数据库)
如果需要把这些差异记录做后续处理(比如删除或迁移),直接基于diffRecords里的数据执行对应的SQL即可,不要去操作原始的ResultSet。
方案二:直接用数据库查询获取差异(更高效)
如果数据量比较大,加载到内存可能占用过多资源,那推荐直接在数据库层面做查询,获取database1.table1中不在database2.table2里的记录:
示例SQL(假设两个库可以跨库查询)
SELECT t1.* FROM database1.table1 t1 LEFT JOIN database2.table2 t2 ON t1.id = t2.id WHERE t2.id IS NULL;
这样直接查询出来的结果就是你需要的差异记录,不需要再手动处理两个ResultSet,效率更高,也避免了JDBC操作的问题。
注意事项
- 一定要确保用来比较的字段是唯一标识(比如主键),避免误判;
- 处理完ResultSet后,记得关闭ResultSet、Statement和Connection,避免资源泄漏;
- 如果数据量极大,方案二优先,减少内存压力。
内容的提问来源于stack exchange,提问作者Rajesh Vaddala
相关产品推荐
相关产品推荐

