MyBatis 動態 SQL 是其核心特性之一,通過 XML 標籤或註解動態拼接 SQL 語句,解決了傳統 SQL 中硬編碼條件、重複代碼、參數為空導致語法錯誤等問題,能根據不同參數值自動生成適配的 SQL,靈活應對多條件查詢、動態插入 / 更新等場景。
if 標籤
if 標籤根據參數值判斷是否拼接標籤內的 SQL 片段(參數非空 / 非默認值時生效)。
<if test="條件表達式">
SQL 片段(如:AND 字段名 = #{參數})
</if>
條件表達式規則:
- 直接引用參數名(如 userName、age)
- 支持邏輯運算:==(等於)、!=(不等於)、&&(且)、||(或)、!(非)
- 字符串判斷:userName != null and userName != ''(非空非空串)
- 數值判斷:age > 18、status == 1
- 集合判斷:list != null and list.size() > 0(集合非空且有元素)。
<select id="selectUserByCondition" resultType="User">
SELECT id, user_name, age, status FROM user
WHERE 1 = 1 <!-- 佔位符,避免條件都不滿足時 WHERE 後無內容 -->
<if test="userName != null and userName != ''">
AND user_name LIKE CONCAT('%', #{userName}, '%')
</if>
<if test="age != null and age > 0">
AND age = #{age}
</if>
</select>
choose、when、otherwise 標籤
多條件分支選擇,僅執行第一個滿足條件的 <when>,若所有 <when> 不滿足,執行 <otherwise>(可選)。
<choose>
<when test="條件1">SQL 片段1</when>
<when test="條件2">SQL 片段2</when>
<otherwise>默認 SQL 片段</otherwise>
</choose>
<select id="selectUserByChoose" resultType="User">
SELECT id, user_name, age, status FROM user
<where>
<choose>
<when test="userName != null and userName != ''">
AND user_name LIKE CONCAT('%', #{userName}, '%')
</when>
<when test="status != null">
AND status = #{status}
</when>
<otherwise>
AND age > 18 <!-- 默認條件:查詢 18 歲以上用户 -->
</otherwise>
</choose>
</where>
</select>
foreach 標籤
遍歷 List、數組、Map 等集合類型參數,拼接成 IN 條件、批量插入的 VALUES 等 SQL 片段。
<foreach
collection="集合參數名" <!-- 集合類型:List→list,數組→array,@Param→註解值 -->
item="遍歷元素別名" <!-- 遍歷集合時的單個元素名稱(如 user、id) -->
index="索引/鍵名" <!-- 可選:List→索引(0,1,2...),Map→key -->
open="片段前綴" <!-- 可選:遍歷結果的開頭(如 "IN (") -->
close="片段後綴" <!-- 可選:遍歷結果的結尾(如 ")") -->
separator="元素分隔符" <!-- 元素之間的分隔符(如 ",") -->
>
#{item} <!-- 引用遍歷元素(如 #{id}、#{user.userName}) -->
</foreach>
<!-- 根據 ID 列表查詢用户 -->
<select id="selectUserByIds" resultType="User">
SELECT id, user_name, age FROM user
<where>
id IN
<foreach collection="idList" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</where>
</select>
<!-- 批量插入用户 -->
<insert id="batchInsertUser">
INSERT INTO user (user_name, age, status)
VALUES
<foreach collection="list" item="user" separator=",">
(#{user.userName}, #{user.age}, #{user.status})
</foreach>
</insert>
where 標籤
自動處理標籤內 SQL 片段的 AND/OR 前綴,無需手動寫 WHERE 1 = 1。
<select id="selectUserByCondition" resultType="User">
SELECT id, user_name, age, status FROM user
<where>
<if test="userName != null and userName != ''">
AND user_name LIKE CONCAT('%', #{userName}, '%')
</if>
<if test="age != null and age > 0">
AND age = #{age}
</if>
</where>
</select>
set 標籤
動態拼接 UPDATE 語句的 SET 子句,自動處理字段後的逗號(避免多餘逗號導致語法錯誤)。
<update id="updateUser" parameterType="User">
UPDATE user
<set>
<if test="userName != null and userName != ''">
user_name = #{userName},
</if>
<if test="age != null">
age = #{age},
</if>
<if test="status != null">
status = #{status}
</if>
</set>
WHERE id = #{id}
</update>
trim 標籤
trim 標籤有4個屬性:
- prefix:給拼接後的 SQL 片段添加前綴
- suffix:給拼接後的 SQL 片段添加後綴
- prefixOverrides:刪除 SQL 片段開頭的指定字符,多個值用 | 分隔
- suffixOverrides:刪除 SQL 片段結尾的指定字符,多個值用 | 分隔
trim 標籤會先拼接 <trim> 內部的 SQL 片段(如 <if> 標籤中的內容), 剔除片段開頭的 prefixOverrides 字符、結尾的 suffixOverrides 字符,給處理後的片段添加 prefix 前綴、suffix 後綴,若內部片段為空(所有 <if> 不生效),則 <trim> 整體不生成任何內容。
sql、include 標籤
<!-- 抽取公共查詢字段 -->
<sql id="userColumns">id, user_name, age, status</sql>
<!-- 引用公共片段 -->
<select id="selectUserById" resultType="User">
SELECT <include refid="userColumns"/> FROM user WHERE id = #{id}
</select>