You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

conn.rollback()抛出未处理SQLException,如何正确使用commit()?

解决事务回滚时的SQLException问题

嘿,我完全懂你现在的困惑——明明已经在catch块里捕获SQLException了,怎么调用conn.rollback()还会抛出未处理的异常?别急,这是因为rollback()方法本身也会抛出SQLException,它和你之前捕获的SQL操作异常是同一类,所以在catch块里调用它时,这个新的异常没有被处理,编译器自然会报错。

接下来给你几个可行的解决方案,顺便帮你优化下代码里的其他小问题:

方案1:在catch块内嵌套try-catch处理回滚异常

这是最直接的方式,把conn.rollback()放在一个内部try-catch里,专门处理回滚时可能出现的异常:

try {
    conn.setAutoCommit(false);
    // 你的SQL语句和循环逻辑...
    conn.commit();
} catch (SQLException e) {
    System.out.println("ERRRROOOOOOORRRRR");
    // 嵌套try-catch处理回滚异常
    try {
        if (conn != null && !conn.isClosed()) {
            conn.rollback();
            System.out.println("事务已回滚");
        }
    } catch (SQLException rollbackEx) {
        System.err.println("回滚失败:" + rollbackEx.getMessage());
    }
} finally {
    // 别忘了恢复自动提交并关闭资源
    try {
        if (conn != null) {
            conn.setAutoCommit(true);
            conn.close();
        }
    } catch (SQLException ex) {
        ex.printStackTrace();
    }
}

方案2:使用try-with-resources(推荐)

Java 7及以上的try-with-resources语法可以自动关闭实现了AutoCloseable接口的资源(比如Connection、PreparedStatement、ResultSet),不仅代码更简洁,还能避免资源泄漏,同时异常处理也更清晰:

// 用try-with-resources自动管理Connection
try (Connection conn = getYourConnection()) { // 替换成你的数据库连接获取逻辑
    conn.setAutoCommit(false);
    
    // 同样用try-with-resources管理PreparedStatement
    try (PreparedStatement selectStatement = conn.prepareStatement("SELECT l.toy_id FROM LETTER l WHERE toy_id=?");
         PreparedStatement deleteStatement = conn.prepareStatement("DELETE FROM TOY WHERE toy_id=?");
         PreparedStatement updateStatement = conn.prepareStatement("INSERT INTO TOY (toy_id, toy_name, price,toy_type, manufacturer) VALUES (?,?,?,?,?)")) {
        
        for (List<String> row : fileContents) {
            int toy_id = getToyId(row);
            
            selectStatement.setInt(1, toy_id);
            try (ResultSet rs = selectStatement.executeQuery()) {
                if (!rs.next()) { // 用rs.next()判断结果集是否为空更通用
                    // 执行删除
                    deleteStatement.setInt(1, toy_id);
                    deleteStatement.executeUpdate();
                } else {
                    // 执行更新(注意:你原来的代码只设了toy_id,其他参数没传会报错!)
                    updateStatement.setInt(1, toy_id);
                    updateStatement.setString(2, row.get(1)); // 假设row索引1对应toy_name
                    updateStatement.setDouble(3, Double.parseDouble(row.get(2))); // price
                    updateStatement.setString(4, row.get(3)); // toy_type
                    updateStatement.setString(5, row.get(4)); // manufacturer
                    updateStatement.executeUpdate();
                }
            }
        }
        conn.commit();
    }
} catch (SQLException e) {
    System.out.println("ERRRROOOOOOORRRRR:" + e.getMessage());
    // 处理回滚异常
    try (Connection conn = getYourConnection()) { // 或确保conn未关闭时直接使用
        if (conn != null && !conn.isClosed()) {
            conn.rollback();
            System.out.println("事务已回滚");
        }
    } catch (SQLException rollbackEx) {
        System.err.println("回滚失败:" + rollbackEx.getMessage());
    }
}

额外提醒几个代码里的小问题

  • 变量名UpdateStatement不符合Java小驼峰命名规范,建议改成updateStatement;
  • 更新操作时,你只设置了toy_id,另外4个必填参数都没赋值,执行时肯定会抛出SQL异常,记得把row里对应的字段补全;
  • 用rs.next()代替rs.first()判断结果集是否为空更稳妥,部分JDBC驱动可能不支持first()方法;
  • 无论事务成功还是失败,都要确保数据库连接等资源被正确关闭,避免连接池泄漏。

内容的提问来源于stack exchange,提问作者frackme

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:15:53