首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

MyBatis 動態 SQL 核心標籤完整指南:if、choose、trim、foreach 實戰詳解

     編輯:Java 綜合教學

前言

MyBatis 的動態 SQL 是其最強大的特性之一,徹底免除了手動拼接 SQL 字串的痛苦與風險。本文系統梳理四大核心標籤——<if>、<choose/when/otherwise>、<trim/where/set>、<foreach> 的語法、適用場景與實戰範例,並分享避坑技巧。

一、<if> —— 多條件組合查詢的基石

最常用的標籤,根據運算式動態決定是否納入 SQL 片段。

1. 基本查詢範例

<select id="getCategory" resultMap="EshopCategory" parameterType="EshopShopCategory">
  SELECT * FROM CATEGORY t
  WHERE 1=1
  <if test="shopCategoryId != null">
    AND t.category_id = #{shopCategoryId}
  </if>
  <if test="shopCategoryName != null">
    AND t.CATEGORY_NAME LIKE CONCAT('%', #{shopCategoryName}, '%')
  </if>
  <if test="shopId == null">
    AND t.shop_id = 0
  </if>
  ORDER BY SEQUENCE_NO
</select>

技巧:WHERE 1=1 讓後續 AND 直接拼接,避免首條件為空導致語法錯誤。

2. 動態 INSERT —— 避免寫入空值

<insert id="addCategory" parameterType="EshopCategory">
  INSERT INTO CATEGORY (
    <if test="shopCategoryName != null and shopCategoryName != ''"> shop_category_name, </if>
    <if test="shopId != null and shopId != ''"> shop_id, </if>
    ADD_TIME
  ) VALUES (
    <if test="shopCategoryName != null and shopCategoryName != ''"> #{shopCategoryName, jdbcType=VARCHAR}, </if>
    <if test="shopId != null and shopId != ''"> #{shopId, jdbcType=NUMERIC}, </if>
    CURRENT_TIMESTAMP
  )
</insert>

適用於資料庫欄位有預設值、不想寫入 NULL 的場景。

3. 動態 UPDATE —— 部分欄位更新

<update id="updateProductCategory" parameterType="EshopShopCategory">
  UPDATE CATEGORY t
  SET
    <if test="shopCategoryName != null"> t.category_name = #{shopCategoryName, jdbcType=VARCHAR}, </if>
    <if test="updateUser != null"> t.update_user = #{updateUser, jdbcType=VARCHAR}, </if>
    t.update_time = CURRENT_TIMESTAMP
  WHERE t.shop_category_id = #{shopCategoryId, jdbcType=NUMERIC}
</update>

只更新傳入非 null 的欄位,極大簡化「部分更新」邏輯。

二、<choose>、<when>、<otherwise> —— 互斥條件分支

類似 Java switch-case-default,只會進入第一個符合條件的 <when>,若皆不符合則進入 <otherwise>。

<select id="findActiveBlogLike" resultType="Blog">
  SELECT * FROM BLOG WHERE state = 'ACTIVE'
  <choose>
    <when test="title != null"> AND title LIKE #{title} </when>
    <when test="author != null and author.name != null"> AND author_name LIKE #{author.name} </when>
    <otherwise> AND featured = 1 </otherwise>
  </choose>
</select>

適用場景:互斥查詢規則(如:依標題搜尋、或依作者搜尋、或預設推薦),避免多條件疊加。

三、<trim>、<where>、<set> —— 解決 SQL 語法殘缺

動態條件最怕產生 WHERE 後無條件、或 SET 後有多餘逗號。MyBatis 提供三標籤自動修剪。

1. <where> —— 智慧處理 WHERE 子句

<select id="findActiveBlogLike" resultType="Blog">
  SELECT * FROM BLOG
  <where>
    <if test="state != null"> state = #{state} </if>
    <if test="title != null"> AND title LIKE #{title} </if>
    <if test="author != null and author.name != null"> AND author_name LIKE #{author.name} </if>
  </where>
</select>
  • 若內容為空 → 不輸出 WHERE。
  • 若首條件以 AND/OR 開頭 → 自動移除。

2. <trim> —— 完全自訂修剪規則

<trim prefix="WHERE" prefixOverrides="AND |OR ">
  <if test="state != null"> AND state = #{state} </if>
  ...
</trim>

等價於 <where>,但可自訂 prefix/suffix/prefixOverrides/suffixOverrides,適用於非標準 SQL 片段。

3. <set> —— 專為 UPDATE 設計

<update id="updateAuthorIfNecessary">
  UPDATE Author
  <set>
    <if test="username != null"> username = #{username}, </if>
    <if test="password != null"> password = #{password}, </if>
    <if test="email != null"> email = #{email}, </if>
    <if test="bio != null"> bio = #{bio} </if>
  </set>
  WHERE id = #{id}
</update>
  • 自動移除末尾多餘逗號。
  • 若所有條件皆不滿足 → 不輸出 SET 關鍵字(避免 UPDATE ... SET WHERE 語法錯誤)。

四、<foreach> —— 集合遍歷與 IN / NOT IN 利器

支援 List、陣列、Map 等集合,自動處理分隔符、括號,極度智慧。

1. 基本語法屬性

屬性說明
collection集合參數名(List→list、陣列→array、或自訂 @Param 名)
item迭代元素別名
index索引別名(List 為索引、Map 為 Key)
open起始字串(如 ()
separator分隔符(如 ,)
close結束字串(如 ))

2. 實戰範例:動態 IN 查詢

<select id="selectPostIn" resultType="domain.blog.Post">
  SELECT * FROM POST P
  WHERE ID IN
  <foreach item="item" index="index" collection="list" open="(" separator="," close=")">
    #{item}
  </foreach>
</select>

傳入 List<Long> ids,MyBatis 自動生成 IN (?, ?, ?) 並綁定參數,防止 SQL 注入。

3. 複雜範例:多表 JOIN 結合動態集合

<select id="selectNumInOrder" resultType="String">
  SELECT COUNT(0) FROM `order` a
  LEFT JOIN item b ON a.ORDER_ID = b.ORDER_ID
  WHERE a.STATUS IN ('1','2','3','5')
  <if test="list != null and list.size() > 0">
    AND b.PHONE_NUM IN
    <foreach item="numberList" collection="list" open="(" separator="," close=")">
      #{numberList.num}
    </foreach>
  </if>
</select>

五、進階技巧與避坑指南

  1. 參數命名:單一 List/陣列參數時,MyBatis 自動以 list/array 為鍵放入 Map;多參數務必用 @Param("xxx") 明確命名。
  2. 防止空集合報錯:<if test="list != null and list.size() > 0"> 包裹 <foreach>,避免 IN () 語法錯誤。
  3. #{ } vs ${ }:#{ } 使用預編譯參數(安全);${ } 直接字串替換(僅用於不可參數化的識別符,如表名、排序欄位),嚴禁用於使用者輸入值。
  4. 效能考量:IN 列表過長(超過 1000)可能導致資料庫解析緩慢,考慮分批或使用臨時表。
  5. 動態 SQL 可讀性:複雜邏輯建議拆分為多個 <sql> 片段再 <include> 組合,保持 Mapper 清晰。

六、總結對照表

標籤核心用途典型場景
<if>布林條件納入多條件查詢、動態 INSERT/UPDATE
<choose/when/otherwise>互斥分支單一查詢規則選擇
<where>自動修剪 WHERE動態條件查詢
<set>自動修剪 SET 尾逗號動態欄位更新
<trim>自訂修剪規則特殊 SQL 片段組裝
<foreach>集合遍歷IN/NOT IN、批次 INSERT VALUES

善用這四大標籤,即可覆蓋 95% 以上的動態 SQL 需求,讓 Mapper XML 既安全又優雅。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved