| 優點 | 缺點 |
|---|---|
| 僅創建時編譯,調用免編譯,效率高 | 業務邏輯下沉 DB,結構變更時維護成本高 |
| 減少網路傳輸(只傳名稱+參數) | 除錯、版本控制較應用層困難 |
| 參數化防 SQL 注入,可細粒度授權 | 跨資料庫移植性差 |
CREATE PROCEDURE proc_name ([IN|OUT|INOUT] param type, ...)
BEGIN
-- body
END
準備工作:建立 fruit 表(id, name, price, address)並插入測試資料。所有範例共用 LinkDB 連線工具類。
-- SQL
DELIMITER $$
CREATE PROCEDURE noParam()
BEGIN SELECT AVG(price) AS priceAvg FROM fruit; END$$
DELIMITER ;
-- Java
CallableStatement cs = conn.prepareCall("{call noParam}");
cs.execute();
ResultSet rs = cs.getResultSet();
-- SQL
CREATE PROCEDURE inTwoParam(IN fruitName VARCHAR(12), IN fruitPrice DECIMAL(9,2))
BEGIN SELECT * FROM fruit WHERE name LIKE CONCAT('%',fruitName,'%') AND price < fruitPrice; END
-- Java
cs = conn.prepareCall("{call inTwoParam(?,?)}");
cs.setString(1, "蓮");
cs.setDouble(2, 88.88); -- DECIMAL 用 setDouble
cs.execute();
-- SQL
CREATE PROCEDURE outTwoParam(OUT fruitName VARCHAR(12), OUT fruitPrice DECIMAL(5,3))
BEGIN
SELECT name INTO fruitName FROM fruit WHERE name='蓮霧';
SELECT price INTO fruitPrice FROM fruit WHERE name='蓮霧';
END
-- 注意:不能合寫成 SELECT name INTO ..., price INTO ...
-- Java
cs = conn.prepareCall("{call outTwoParam(?,?)}");
cs.registerOutParameter(1, Types.VARCHAR);
cs.registerOutParameter(2, Types.DECIMAL);
cs.execute();
String name = cs.getString(1);
double price = cs.getDouble(2);
-- SQL
CREATE PROCEDURE inOneParamAndOutOneParam(IN fruitName VARCHAR(12), OUT fruitPrice DECIMAL(7,3))
BEGIN SELECT price INTO fruitPrice FROM fruit WHERE name=fruitName; END
-- Java
cs.setString(1, "蓮霧");
cs.registerOutParameter(2, Types.DECIMAL);
cs.execute();
-- SQL
CREATE PROCEDURE inOneParamISOutOneParam(INOUT fruitName VARCHAR(12))
BEGIN SELECT name INTO fruitName FROM fruit WHERE name LIKE CONCAT('%',fruitName,'%') LIMIT 1; END
-- Java
cs.setString(1, "蓮");
cs.registerOutParameter(1, Types.VARCHAR); -- 同一位置註冊
cs.execute();
String result = cs.getString(1);
DELIMITER $$ ... $$ DELIMITER ; 中 $$ 前後**只能有一個空格**,多空格會導致建立失敗。CONCAT('%', param, '%') 不能寫成 '%' + param + '%'(MySQL 無 + 連接運算子)。INTO 子句位置:SELECT ... INTO var FROM ... 或 SELECT ... FROM ... INTO var,不可置於 LIMIT 之後。DECIMAL 對應 setDouble/getDouble,VARCHAR 對應 setString/getString。