首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

Java SQLException: After end of result set 根因分析與防範模式

     編輯:關於SqlServer

錯誤訊息

java.sql.SQLException: After end of result set

根本原因

嘗試存取已關閉或已耗盡的 ResultSet 物件。常見於同一 Connection 或 Statement 重複執行查詢,導致前一個 ResultSet 隱性關閉。

典型錯誤程式碼

// 第一次查詢
String sql1 = "SELECT stateId FROM state WHERE stateMessage = ?";
ResultSet rs1 = con.executeQuery(sql1);
while (rs1.next()) {
    stateId = String.valueOf(rs1.getInt(1));
}

// 第二次查詢 - 同一 Statement/Connection
String sql2 = "SELECT adminId FROM admin WHERE adminRealName = ?";
ResultSet rs2 = con.executeQuery(sql2);  // 隱性關閉 rs1!
while (rs2.next()) {
    adminId = String.valueOf(rs1.getInt(1));  // 錯誤:仍使用 rs1 而非 rs2
}

JDBC 規範行為

  • 同一 Statement 執行新查詢,舊 ResultSet 自動關閉。
  • 同一 Connection 在自動認交模式下,新 Statement 可能導致舊 ResultSet 失效(視驅動實作)。
  • 已關閉的 ResultSet 呼叫任何方法拋出此異常。

正確模式:獨立資源、確實關閉

// 使用 try-with-resources (Java 7+)
try (PreparedStatement ps1 = con.prepareStatement(sql1);
     ResultSet rs1 = ps1.executeQuery()) {
    while (rs1.next()) {
        stateId = String.valueOf(rs1.getInt(1));
    }
}

try (PreparedStatement ps2 = con.prepareStatement(sql2);
     ResultSet rs2 = ps2.executeQuery()) {
    while (rs2.next()) {
        adminId = String.valueOf(rs2.getInt(1));  // 正確使用 rs2
    }
}

防範檢查清單

  1. 每個查詢使用獨立 PreparedStatement。
  2. 使用 try-with-resources 確保 ResultSet、Statement、Connection 正確關閉。
  3. 避免在迴圈中重複使用單一 Statement 執行多次查詢。
  4. 檢查連線池設定:maxOpenPreparedStatements 避免語句快取導致非預期關閉。
  5. 啟用 JDBC 驅動除錯日誌追蹤 ResultSet 生命週期。

進階:連線池與 Statement Cache 陷阱

某些連線池(如 DBCP、HikariCP)預設啟用 Statement Cache,prepareStatement 可能回傳快取的 Statement 物件。若前一次查詢的 ResultSet 尚未完全消費就再次呼叫,會觸發隱性關閉。解決:
- 關閉 Statement Cache(效能代價)
- 確保每次查詢完整消費 ResultSet 後再歸還連線
- 使用 SET HOLD_CURSORS_OVER_COMMIT 相容模式(視資料庫支援)

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved