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

如何计算指定项目任务完成率并解决JDBC ResultSet关闭异常?

问题分析与解决方案

核心问题

  1. ResultSet关闭异常原因:同一个Statement对象执行第二个executeQuery时,会自动关闭之前打开的ResultSet,导致后续访问第一个ResultSet时抛出"The result set is closed"异常。
  2. SQL冗余与硬编码:原代码用两次查询获取数据,效率低且sql2中硬编码了p_id=2,没有使用传入的动态id。
  3. SQL注入风险:直接通过字符串拼接id到SQL语句中,存在SQL注入漏洞。

优化方案

1. 合并SQL查询(一次获取完成数与总数)

用单条SQL语句同时统计指定项目的已完成任务数和总任务数,避免多次查询:

SELECT 
    SUM(CASE WHEN state = 1 THEN 1 ELSE 0 END) AS finishedTasks,
    COUNT(*) AS totalTasks
FROM tasks 
WHERE p_id = ?
  • SUM(CASE...):统计state=1的任务数量(已完成)
  • COUNT(*):统计该项目的总任务数
  • ?是参数占位符,用于后续传入动态p_id,避免SQL注入

2. 修改Java代码(修复异常+安全查询)

使用PreparedStatement替代Statement,同时利用try-with-resources自动关闭连接、语句和结果集,避免资源泄漏:

修改后的projectProgress方法

public void projectProgress() throws SQLException, ClassNotFoundException {
    int id = Integer.parseInt(PMprogressFrame.Pnum.getText());
    String sql = "SELECT SUM(CASE WHEN state = 1 THEN 1 ELSE 0 END) AS finishedTasks, COUNT(*) AS totalTasks FROM tasks WHERE p_id = ?";

    // 使用try-with-resources自动关闭资源
    try (SqlConnection DB = new SqlConnection();
         PreparedStatement pstmt = DB.conn.prepareStatement(sql)) {
        
        pstmt.setInt(1, id); // 设置参数,避免SQL注入
        ResultSet result = pstmt.executeQuery();

        if (result.next()) {
            float finished = result.getFloat("finishedTasks");
            float total = result.getFloat("totalTasks");
            float progress = 0.0f;
            // 处理总任务数为0的情况,避免除以0错误
            if (total > 0) {
                progress = (finished / total) * 100;
            }
            PMprogressFrame.progress.setText(String.format("%.2f%%", progress)); // 保留两位小数更友好
        }
    }
}

调整SqlConnection类(可选优化)

为了更规范,建议将Statement改为局部变量,避免成员变量复用导致的问题:

public class SqlConnection {
    public Connection conn;

    public SqlConnection() throws SQLException, ClassNotFoundException {
        Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
        String connectionUrl = "jdbc:sqlserver://MEMENTOMORI:1433;databaseName=PMS;user=sa;password=12345;encrypt=false";
        conn = DriverManager.getConnection(connectionUrl);
    }
}
  • 移除了成员变量st和rs,避免复用带来的资源冲突
  • 不再需要allowMultiQueries=true,因为已经合并为单条查询

关键注意事项

  • 资源管理:必须确保Connection、PreparedStatement、ResultSet在使用后关闭,try-with-resources会自动处理这些操作,避免内存泄漏。
  • 除数为0处理:当项目总任务数为0时,直接计算会抛出算术异常,需要先判断total > 0再计算完成率。
  • SQL注入防护:始终使用PreparedStatement的参数占位符传递动态值,禁止直接拼接字符串到SQL语句中。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 17:35:13