本文通過一個具體的「兩數相乘」示例,詳細演示如何在 MySQL 中創建帶輸出參數的存儲過程,並使用 JDBC 的 CallableStatement 進行調用、參數綁定與結果獲取。
登入 MySQL 客戶端,執行以下腳本:
DELIMITER //
DROP PROCEDURE IF EXISTS add_pro //
CREATE PROCEDURE add_pro(
IN a INT,
IN b INT,
OUT sum INT
)
BEGIN
SET sum = a * b;
END //
DELIMITER ;
關鍵點解析:
DELIMITER //:臨時修改語句結束符,避免過程體內的 ; 提前終止創建語句。IN:輸入參數;OUT:輸出參數;亦可用 INOUT 表示雙向參數。OUT 參數即可返回結果。package com.example.demo;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Types;
public class CallableStatementDemo {
private static final String URL = "jdbc:mysql://127.0.0.1:3306/test?useSSL=false&serverTimezone=UTC";
private static final String USER = "root";
private static final String PASSWORD = "123456";
private static final String DRIVER = "com.mysql.cj.jdbc.Driver"; // MySQL 8.0+ 驅動類
public static void main(String[] args) {
Connection conn = null;
CallableStatement cstmt = null;
try {
// 1. 加載驅動(JDBC 4.0+ 可省略,保留兼容性)
Class.forName(DRIVER);
// 2. 建立連接
conn = DriverManager.getConnection(URL, USER, PASSWORD);
// 3. 準備調用語法:{CALL 過程名(?, ?, ?)} 佔位符對應 IN/IN/OUT
String sql = "{CALL add_pro(?, ?, ?)}";
cstmt = conn.prepareCall(sql);
// 4. 綁定輸入參數(索引從 1 開始)
cstmt.setInt(1, 122); // a
cstmt.setInt(2, 2); // b
// 5. 註冊輸出參數類型(關鍵步驟!)
cstmt.registerOutParameter(3, Types.INTEGER);
// 6. 執行存儲過程
cstmt.execute();
// 7. 獲取輸出參數值
int result = cstmt.getInt(3);
System.out.println("計算結果 (122 * 2) = " + result); // 輸出 244
} catch (Exception e) {
e.printStackTrace();
} finally {
// 8. 釋放資源(逆序關閉)
try { if (cstmt != null) cstmt.close(); } catch (Exception ignore) {}
try { if (conn != null) conn.close(); } catch (Exception ignore) {}
}
}
}
| 方法 | 說明 |
|---|---|
Connection.prepareCall(String sql) | 創建 CallableStatement 對象,預編譯調用語句 |
setXxx(int idx, Xxx val) | 綁定 IN/INOUT 參數,idx 為佔位符位置(1-based) |
registerOutParameter(int idx, int sqlType) | 註冊 OUT/INOUT 參數的 JDBC 類型(java.sql.Types) |
execute() | 執行存儲過程,返回 boolean(是否有 ResultSet) |
getXxx(int idx) | 獲取 OUT/INOUT 參數值 |
若存儲過程包含 SELECT 語句,執行後可獲取 ResultSet:
boolean hasResults = cstmt.execute();
if (hasResults) {
try (ResultSet rs = cstmt.getResultSet()) {
while (rs.next()) { /* 處理行數據 */ }
}
// 如有多個結果集,需循環 cstmt.getMoreResults() 獲取
}
cstmt.setInt("a", 122); // 按參數名綁定,無需記住順序
cstmt.registerOutParameter("sum", Types.INTEGER);
int result = cstmt.getInt("sum");
START TRANSACTION; COMMIT/ROLLBACK;),或在 Java 端設置 conn.setAutoCommit(false) 統一控制。registerOutParameter 的索引必須與 {CALL ... (?, ?, ?)} 中佔位符位置一致。BIGINT 對應 Types.BIGINT/getLong(),DECIMAL 對應 Types.DECIMAL/getBigDecimal()。com.mysql.cj.jdbc.Driver,舊驅動 com.mysql.jdbc.Driver 已棄用。JDBC 調用 MySQL 存儲過程的核心流程是:定義 SQL 調用語法 → 準備 CallableStatement → 綁定輸入參數 → 註冊輸出參數類型 → 執行 → 讀取輸出值 → 關閉資源。掌握 registerOutParameter 類型映射與資源釋放順序,即可穩健應對各類存儲過程調用場景。