MyBatis 作為優秀的持久層框架,不僅支援基本 SQL 查詢,也能輕鬆整合資料庫 View(視圖) 與 Stored Procedure(預存程序)。本文透過完整程式碼示範,說明如何在 Mapper XML、Mapper 介面、Service 層分別配置與呼叫。
視圖本質上是一個虛擬資料表,MyBatis 呼叫方式與一般 SELECT 無異。
<!-- 查詢收益明細視圖 -->
<select id="getContactEarnsDetail" resultType="java.util.Map" parameterType="java.lang.Integer">
SELECT title, trade_time, trade_amount
FROM v_contacts_earn
WHERE user_id = #{userId}
</select>
resultType="java.util.Map":每筆資料對應一個 Map<String, Object>,鍵為欄位名。parameterType="java.lang.Integer":輸入參數為單一 userId。List<Map<String, Object>> getContactEarnsDetail(Integer userId);
@Override
public List<Map<String, Object>> getContactEarnsDetail(Integer userId) {
Assert.notNull(userId, "userId 不得為空");
return contactEarnsMapper.getContactEarnsDetail(userId);
}
MyBatis 透過 statementType="CALLABLE" 支援預存程序,分「有回傳結果集」與「無回傳結果集」兩種情境。
預存程序定義:
CREATE PROCEDURE p_my_wallet(IN var_user_id INT)
BEGIN
-- 回傳三欄:revenue_today, revenue_contacts, balance
SELECT ...;
END
Mapper XML:
<select id="getMyWallet" parameterType="java.lang.Integer" resultType="java.util.Map" statementType="CALLABLE">
{ CALL p_my_wallet( #{userId, jdbcType=INTEGER, mode=IN} ) }
</select>
statementType="CALLABLE":告知 MyBas 這是預存程序呼叫。#{userId, jdbcType=INTEGER, mode=IN}:明確指定參數型別與模式。Mapper 介面:
Map<String, Object> getMyWallet(@Param("userId") Integer userId);
Mapper XML:
<select id="cardBuild" statementType="CALLABLE">
<![CDATA[
{ CALL p_insert_card_build_info (
#{is_customized, mode=IN, jdbcType=INTEGER},
#{face_value, mode=IN, jdbcType=INTEGER},
#{number, mode=IN, jdbcType=INTEGER}
) }
]]>
</select>
<![CDATA[ ... ]]> 避免特殊字元衝突。id="cardBuild" 對應 Mapper 介面的 void cardBuild(...)。EXECUTE 權限。ResultSetHandler 自行處理。IN、OUT、INOUT 需與資料庫定義一致,否則會拋出例外。MyBatis 整合 View 與 Stored Procedure 直觀且彈性,關鍵在於 XML 中正確設定 statementType、參數模式與結果型別。善用視圖簡化複雜查詢,善用預存程序封裝業務邏輯,能有效提升系統可維護性與效能。