CREATE TABLE p_user (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(20),
sex CHAR(1) -- '男' 或 '女'
);
INSERT INTO p_user(name, sex) VALUES('A', '男');
INSERT INTO p_user(name, sex) VALUES('B', '女');
INSERT INTO p_user(name, sex) VALUES('C', '男');
-- 存儲過程:統計性別人數
DELIMITER $
CREATE PROCEDURE ges_user_count(IN sex_id INT, OUT user_count INT)
BEGIN
IF sex_id = 0 THEN
SELECT COUNT(*) FROM p_user WHERE sex = '女' INTO user_count;
ELSE
SELECT COUNT(*) FROM p_user WHERE sex = '男' INTO user_count;
END IF;
END $
DELIMITER ;
-- 測試調用
SET @user_count = 0;
CALL ges_user_count(0, @user_count);
SELECT @user_count; -- 返回 1
<mapper namespace="me.gacl.mapping.userMapper">
<!-- statementType="CALLABLE" 聲明調用存儲過程 -->
<select id="getUserCount" statementType="CALLABLE" parameterMap="countParamMap">
CALL ges_user_count(?, ?)
</select>
<!-- 參數映射:IN/OUT 方向、JDBC 類型 -->
<parameterMap id="countParamMap" type="java.util.Map">
<parameter property="sexid" mode="IN" jdbcType="INTEGER"/>
<parameter property="usercount" mode="OUT" jdbcType="INTEGER"/>
</parameterMap>
</mapper>
public class StoredProcTest {
@Test
public void testGetUserCount() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
String statement = "me.gacl.mapping.userMapper.getUserCount";
// 必須使用 Map 傳遞 IN/OUT 參數
Map<String, Integer> paramMap = new HashMap<>();
paramMap.put("sexid", 0); // IN 參數:0=女, 1=男
paramMap.put("usercount", -1); // OUT 參數:初始值任意
// 執行調用(返回值通常為 null,結果在 paramMap 中)
sqlSession.selectOne(statement, paramMap);
// 獲取 OUT 參數結果
Integer result = paramMap.get("usercount");
System.out.println("統計結果: " + result); // 輸出 1
sqlSession.close();
}
}
CALL proc(?, ?) 順序必須與 parameterMap 定義順序一致若存儲過程返回結果集(REF CURSOR),需配合 resultMap 映射:
<select id="getUsers" statementType="CALLABLE" resultMap="userMap">
CALL get_users(?, ?)
</select>
<parameterMap id="procParams" type="map">
<parameter property="deptId" mode="IN" jdbcType="INTEGER"/>
<parameter property="cursor" mode="OUT" jdbcType="CURSOR"
javaType="java.sql.ResultSet" resultMap="userMap"/>
</parameterMap>
注意:不同數據庫對游標支持不同(Oracle 支持良好,MySQL 需 8.0+ 且配置特定驅動)。
| 優點 | 缺點 |
|---|---|
| 業務邏輯下沉數據庫,減少網絡交互 | 業務邏輯分散,難以版本控制與單元測試 |
| 複雜統計/報表性能優於多次查詢 | 數據庫鎖定時間長,影響併發 |
| 利用數據庫原生能力(臨時表、窗口函數) | 移植性差,綁定特定數據庫方言 |
建議:核心業務邏輯保持在 Java 層,僅在極度複雜的統計報表、批量數據處理場景考慮存儲過程。