如何将CachedRowSet中多行修改保存到数据库?
问题:CachedRowSet批量更新记录无法同步到数据库
我正在编写一个更新CachedRowSet中记录的程序,但目前仅能保存单条记录的修改。当CachedRowSet包含多条记录时,遍历修改后无法将变更同步到数据库。
我能正常从数据库获取数据,使用CachedRowSet是为了实现断开连接模式,以支持大量用户访问避免应用卡顿。我了解PreparedStatement可防范SQL注入,但该程序仅我个人使用。
以下代码用于将主表的新ID更新到子表的外键字段:原制造系统未使用自增ID,采用字符型ID,现在要改为自增ID,需批量更新子表外键。
private void FillForeignKey(String strDeprecated_Id_Column, String strChild_Table_Name, String strChildForeignKey_Column, Integer intNewMaster_Id, String strOldMaster_Id) throws SQLException { try { Connection connection = getConnection("jdbc:mysql://127.0.0.1:5222/jobtrack", "root", ""); //Select Master table with String seqlChild = "SELECT " + strDeprecated_Id_Column + ", " + strChildForeignKey_Column + " FROM " + strChild_Table_Name + " Where " + strDeprecated_Id_Column +" = " + "'" + strOldMaster_Id + "'"; System.out.println(seqlChild); Statement stChild = connection.createStatement(); ResultSet rsChild = stChild.executeQuery(seqlChild); RowSetFactory factory = RowSetProvider.newFactory(); CachedRowSet crsetChild = factory.createCachedRowSet(); crsetChild.populate(rsChild); rsChild.close(); //connection.close(); connection.setAutoCommit(false); System.out.println("Child Rowset Size " + crsetChild.size()); System.out.println("New Id " + intNewMaster_Id); System.out.println("Old Id " + strOldMaster_Id); while (crsetChild.next()) { crsetChild.updateInt(strChildForeignKey_Column, intNewMaster_Id); crsetChild.moveToCurrentRow(); System.out.println("Data From child Rowset " + crsetChild.getInt(strChildForeignKey_Column)); crsetChild.updateRow(); crsetChild.acceptChanges(connection); } crsetChild.close(); //connection.close(); }catch (SQLException e) { System.out.println(e.getMessage()); } }
解决方案
核心问题是每次循环内调用acceptChanges(connection):该方法会立即同步当前所有变更到数据库,并重置CachedRowSet的变更标记。第一次同步后,后续修改的记录因标记被清空,无法再次触发同步。
修改后的代码将同步操作移到循环外,同时优化资源管理和事务控制:
private void FillForeignKey(String strDeprecated_Id_Column, String strChild_Table_Name, String strChildForeignKey_Column, Integer intNewMaster_Id, String strOldMaster_Id) throws SQLException { // try-with-resources自动管理资源,避免泄漏 try (Connection connection = getConnection("jdbc:mysql://127.0.0.1:5222/jobtrack", "root", ""); Statement stChild = connection.createStatement()) { String sqlChild = "SELECT " + strDeprecated_Id_Column + ", " + strChildForeignKey_Column + " FROM " + strChild_Table_Name + " WHERE " + strDeprecated_Id_Column + " = '" + strOldMaster_Id + "'"; System.out.println(sqlChild); try (ResultSet rsChild = stChild.executeQuery(sqlChild)) { RowSetFactory factory = RowSetProvider.newFactory(); CachedRowSet crsetChild = factory.createCachedRowSet(); crsetChild.populate(rsChild); System.out.println("Child Rowset Size " + crsetChild.size()); System.out.println("New Id " + intNewMaster_Id); System.out.println("Old Id " + strOldMaster_Id); // 遍历标记所有需要修改的行 while (crsetChild.next()) { crsetChild.updateInt(strChildForeignKey_Column, intNewMaster_Id); System.out.println("Data From child Rowset " + crsetChild.getInt(strChildForeignKey_Column)); crsetChild.updateRow(); // 标记当前行已修改 } // 所有行修改完成后,一次性同步到数据库 connection.setAutoCommit(false); crsetChild.acceptChanges(connection); connection.commit(); crsetChild.close(); } catch (SQLException e) { connection.rollback(); // 异常时回滚事务 System.out.println(e.getMessage()); throw e; } } catch (SQLException e) { System.out.println(e.getMessage()); } }
关键修改说明
- 批量同步变更:将
acceptChanges(connection)移到循环外,让CachedRowSet收集所有修改后一次性提交,避免每次同步重置变更标记。 - 自动资源管理:使用try-with-resources语法,自动关闭Connection、Statement、ResultSet,无需手动调用close()。
- 事务控制:开启手动提交模式,同步完成后手动提交,异常时回滚,保证数据一致性。
- 移除冗余代码:删除
moveToCurrentRow(),next()已经定位到当前行,修改后直接调用updateRow()即可标记变更。
内容的提问来源于stack exchange,提问作者Rocco Szabo
相关产品推荐
相关产品推荐

