首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

Java 執行存儲過程獲取更新行數為 -1 的原因與解決

     編輯:程式設計疑難解答

問題現象

呼叫建立/刪除暫存表的存儲過程,CallableStatement.getUpdateCount() 回傳 -1,導致誤判為執行失敗。

根本原因

getUpdateCount() 回傳值定義 (JDBC 規範):

  • >= 0:影響的行數 (DML: INSERT/UPDATE/DELETE)
  • -1:非 DML 語句 (DDL: CREATE/DROP/ALTER、SET、CALL 等) 或 結果集 (SELECT)
  • -2:未知 (批次執行、尚未完成)

建立/刪除暫存表屬於 DDL,不產生「影響行數」,故回傳 -1 屬正常行為,不代表失敗。

正確判斷執行成功邏輯

CallableStatement cs = conn.prepareCall("{call PROC_TEMP}");
boolean hasResult = cs.execute(); // 執行,回傳 true 表示有 ResultSet

// 處理多重結果 (存儲過程可能回傳多個 ResultSet/更新計數)
while (true) {
    int updateCount = cs.getUpdateCount();
    if (updateCount != -1) {
        // DML 更新計數
        System.out.println("更新行數: " + updateCount);
    } else {
        // 可能是 ResultSet 或無結果
        ResultSet rs = cs.getResultSet();
        if (rs != null) {
            // 處理結果集
            while (rs.next()) { /* ... */ }
            rs.close();
        } else {
            // 真正結束
            break;
        }
    }
    
    // 檢查是否還有下一個結果
    if (!cs.getMoreResults()) {
        break;
    }
}

cs.close();

存儲過程最佳實踐

1. 明確回傳狀態碼

CREATE PROCEDURE PROC_TEMP
    @ResultCode INT OUTPUT
AS
BEGIN
    SET NOCOUNT ON; -- 關閉 DONE_IN_PROC 訊息,減少網路傳輸
    
    BEGIN TRY
        IF OBJECT_ID('tempdb..##temp') IS NOT NULL
            DROP TABLE ##temp;
        
        SELECT IDENTITY(INT) AS id, * 
        INTO ##temp 
        FROM AlarmRecordRe 
        ORDER BY [TIMESTAMP] DESC;
        
        SET @ResultCode = 0; -- 成功
    END TRY
    BEGIN CATCH
        SET @ResultCode = ERROR_NUMBER(); -- 失敗回傳錯誤碼
    END CATCH
END

2. Java 端讀取輸出參數

CallableStatement cs = conn.prepareCall("{call PROC_TEMP(?)}");
cs.registerOutParameter(1, Types.INTEGER);
cs.execute();
int resultCode = cs.getInt(1);
if (resultCode == 0) {
    System.out.println("存儲過程執行成功");
} else {
    System.out.println("存儲過程失敗,錯誤碼: " + resultCode);
}

3. 動態 SQL 安全模式 (各資料庫)

資料庫動態建表/刪表範例
MySQLPREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
OracleEXECUTE IMMEDIATE 'DROP TABLE ' || table_name || ' PURGE';
SQL ServerEXEC sp_executesql @sql;
PostgreSQLEXECUTE format('DROP TABLE IF EXISTS %I', table_name);

常見誤區

誤區正確觀念
getUpdateCount() == -1 表示失敗-1 表示非 DML 或結果集,DDL 正常回傳 -1
execute() 回傳 false 表示失敗false 表示無 ResultSet (可能是更新計數或無結果)
不需關閉 CallableStatement必須 close() 釋放資料庫游標與連線資源

除錯技巧

// 開啟 JDBC 詳細日誌 (log4j2/logback)



// 或程式碼層面
cs.execute();
System.out.println("execute() 回傳: " + hasResult);
System.out.println("getUpdateCount(): " + cs.getUpdateCount());
ResultSet rs = cs.getResultSet();
System.out.println("getResultSet(): " + (rs != null ? "有結果集" : "無"));
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved