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 執行動態 SQLEXECUTE 產生一個結果集,順序返回給呼叫端DEALLOCATE PREPARE 釋放預備語句資源,避免洩漏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) {}
}
}
| 方法 | 用途 |
|---|---|
prepareCall("{call proc(?,?)}") | 建立可呼叫預存程序的 Statement |
execute() | 執行,返回 true 表示第一個結果集可用 |
getResultSet() | 取得當前結果集 |
getMoreResults() | 移至下一個結果集,無則返回 false |
PREPARE stmt FROM ? + EXECUTE stmt USING @param 防注入ResultSetMetaData 可動態獲取欄位名/型別,支援通用處理邏輯DECLARE CONTINUE HANDLER FOR SQLEXCEPTION 捕獲錯誤並記錄autoCommit 設定正確,預存程序內若有事務需顯式 COMMIT/ROLLBACK掌握「預存程序 + 多結果集 + JDBC 遍歷」模式,能優雅解決單次呼叫多查詢的需求,是資料庫應用開發的進階必備技能。