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

SonarQube提示需关闭PreparedStatement但已在finally实现仍报错怎么办

问题解决方法

告警触发原因

你的现有代码存在明确的资源泄露风险,并非SonarQube误报:

  • PreparedStatement的初始化语句this.connection.prepareStatement(sql)、参数赋值语句preparedStatement.setString(1, id)都写在try块外部,如果这两行代码抛出SQLException,代码不会进入后续的try-finally逻辑,PreparedStatement资源完全不会被关闭
  • 执行查询得到的ResultSet资源没有做任何关闭处理,同样存在资源泄露风险

最优解决方案

Java 7及以上版本中,JDBC的Connection、Statement、ResultSet都实现了AutoCloseable接口,直接使用try-with-resources语法即可自动处理资源关闭,完全符合SonarQube的规则要求,修改后代码如下:

public String getUserEmail(String id) throws SQLException {
    String emailAddress = null;
    String sql = "select email from my_table where id=?";
    // 将PreparedStatement、ResultSet都放在try-with-resources声明中,执行结束会自动按逆序关闭资源
    try (PreparedStatement preparedStatement = this.connection.prepareStatement(sql)) {
        preparedStatement.setString(1, id);
        try (ResultSet rs = preparedStatement.executeQuery()) {
            while (rs.next()) {
                emailAddress = rs.getString("email");
            }
        }
    } catch(SQLException e) {
        throw new TuringClientException("Failed to getUserEmail. ", e);
    }
    return emailAddress;
}

如果需要兼容Java 6及更早版本,必须手动处理资源的非空判断、异常捕获,写法如下:

public String getUserEmail(String id) throws SQLException {
    String emailAddress = null;
    String sql = "select email from my_table where id=?";
    PreparedStatement preparedStatement = null;
    ResultSet rs = null;
    try {
        preparedStatement = this.connection.prepareStatement(sql);
        preparedStatement.setString(1, id);
        rs = preparedStatement.executeQuery();
        while (rs.next()) {
            emailAddress = rs.getString("email");
        }
    } catch(SQLException e) {
        throw new TuringClientException("Failed to getUserEmail. ", e);
    } finally {
        // 先关闭ResultSet,再关闭Statement,关闭操作单独捕获异常避免覆盖业务异常
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                // 可按业务需求打印日志或忽略
            }
        }
        if (preparedStatement != null) {
            try {
                preparedStatement.close();
            } catch (SQLException e) {
                // 可按业务需求打印日志或忽略
            }
        }
    }
    return emailAddress;
}

两种方案修改后都可以消除SonarQube的告警,优先推荐使用try-with-resources的写法,代码更简洁且不会出现手动关闭的逻辑疏漏。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 11:27:03