首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

MySQL 預存程序 返回多結果集實戰:動態 SQL + Java 呼叫範例

     編輯:MySQL 資料庫相關知識

MySQL 函數只能返回單一值,需返回多結果集時必須使用預存程序。本文展示一個接受兩條動態 SQL、依序執行並返回兩個結果集的預存程序,並提供完整的 Java JDBC 呼叫代碼(使用 CallableStatement 處理多結果集)。

一、預存程序定義

DROP PROCEDURE IF EXISTS `testguocheng`;

CREATE PROCEDURE `testguocheng`(
    IN `sql1` VARCHAR(1000),
    IN `sql2` VARCHAR(1000)
)
BEGIN
    -- 第一個結果集
    SET @SQLStr1 = CONCAT(sql1);
    PREPARE stmt1 FROM @SQLStr1;
    EXECUTE stmt1;
    DEALLOCATE PREPARE stmt1;

    -- 第二個結果集
    SET @SQLStr2 = CONCAT(sql2);
    PREPARE stmt2 FROM @SQLStr2;
    EXECUTE stmt2;
    DEALLOCATE PREPARE stmt2;
END;

關鍵點:

  • 使用 PREPARE ... FROM @var + EXECUTE 執行動態 SQL
  • 每個 EXECUTE 產生一個結果集,順序返回給呼叫端
  • DEALLOCATE PREPARE 釋放預備語句資源,避免洩漏
  • 參數長度設為 1000 以容納完整 SQL 文本

二、Java JDBC 呼叫代碼

public static void getData() {
    Connection conn = null;
    CallableStatement stmt = null;
    ResultSet rs = null;

    try {
        conn = JdbcUtils.getConnection();  // 自行實現連線池取得
        // 呼叫預存程序,傳入兩條 SQL
        String callSql = "{call testguocheng('SELECT * FROM tsys_user;', 'SELECT COUNT(*) FROM tsys_user;')}";
        stmt = conn.prepareCall(callSql);

        boolean hasResult = stmt.execute();
        int resultSetIndex = 0;

        while (hasResult) {
            resultSetIndex++;
            System.out.println("=== 第 " + resultSetIndex + " 個結果集 ===");
            rs = stmt.getResultSet();

            if (resultSetIndex == 1) {
                // 第一個結果集:用戶明細
                while (rs.next()) {
                    System.out.println("uid: " + rs.getString("uid") 
                        + ", uname: " + rs.getString("uname"));
                }
            } else {
                // 第二個結果集:統計總數
                while (rs.next()) {
                    System.out.println("總數:" + rs.getString(1));
                }
            }

            // 移至下一個結果集
            hasResult = stmt.getMoreResults();
            if (rs != null) { rs.close(); rs = null; }
        }
    } catch (Exception e) {
        System.out.println("Error: " + e.toString());
    } finally {
        try { if (rs != null) rs.close(); } catch (Exception ignore) {}
        try { if (stmt != null) stmt.close(); } catch (Exception ignore) {}
        try { if (conn != null) conn.close(); } catch (Exception ignore) {}
    }
}

三、關鍵 API 說明

方法用途
prepareCall("{call proc(?,?)}")建立可呼叫預存程序的 Statement
execute()執行,返回 true 表示第一個結果集可用
getResultSet()取得當前結果集
getMoreResults()移至下一個結果集,無則返回 false

四、進階擴展建議

  • 參數化動態 SQL:避免直接拼接字串,改用 PREPARE stmt FROM ? + EXECUTE stmt USING @param 防注入
  • 結果集元資料:ResultSetMetaData 可動態獲取欄位名/型別,支援通用處理邏輯
  • 異常處理:預存程序內用 DECLARE CONTINUE HANDLER FOR SQLEXCEPTION 捕獲錯誤並記錄
  • 連線池配合:確保 autoCommit 設定正確,預存程序內若有事務需顯式 COMMIT/ROLLBACK

五、適用場景

  • 單次呼叫需返回多張邏輯無關的結果集(如:明細 + 統計、主表 + 從表)
  • 減少網路往返,將多條查詢封裝在伺服器端執行
  • 舊系統重構,將商務邏輯下沉至資料庫層

掌握「預存程序 + 多結果集 + JDBC 遍歷」模式,能優雅解決單次呼叫多查詢的需求,是資料庫應用開發的進階必備技能。

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