MyBatis 動態 SQL 基於 OGNL 表達式語言,在 XML 中通過標籤實現條件判斷、循環遍歷、片段拼接,將 Java 流程控制邏輯映射到 SQL 構建過程,實現「一條 SQL 應對多種查詢場景」。本文系統講解 5 大核心標籤的語法、屬性、常見陷阱與最佳實踐。
適用於數據庫不支持自增、或使用序列/自定義函數生成主鍵的場景。
<insert id="createStudentAutoKey" parameterType="StudentEntity" keyProperty="studentId">
<selectKey keyProperty="studentId" resultType="String" order="BEFORE">
select nextval('student_seq') -- Oracle 序列 / 自定義函數
</selectKey>
INSERT INTO STUDENT_TBL(STUDENT_ID, STUDENT_NAME, ...)
VALUES (#{studentId}, #{studentName}, ...)
</insert>
關鍵屬性:
order="BEFORE":先查主鍵,再執行 INSERT(適用序列/函數)order="AFTER":先執行 INSERT,再查主鍵(適用自增/identity)statementType:STATEMENT/PREPARED/CALLABLE,默認 PREPARED<select id="getStudentListIf" resultMap="studentResultMap" parameterType="StudentEntity">
SELECT * FROM STUDENT_TBL ST
<where>
<if test="studentName != null and studentName != ''">
AND ST.STUDENT_NAME LIKE CONCAT('%', #{studentName}, '%')
</if>
<if test="studentSex != null">
AND ST.STUDENT_SEX = #{studentSex}
</if>
<if test="classId != null and classId != ''">
AND ST.CLASS_ID = #{classId}
</if>
</where>
</select>
classEntity.classId != nullids != null and ids.size() > 0name != null and name != ''(推薦寫法)自動處理:
WHERE 關鍵字AND/OR<where>
<if test="state != null"> state = #{state} </if>
<if test="title != null"> AND title LIKE #{title} </if>
<if test="author != null"> AND author_name LIKE #{author.name} </if>
</where>
<!-- 等價於 where -->
<trim prefix="WHERE" prefixOverrides="AND |OR ">
<if test="state != null"> state = #{state} </if>
<if test="title != null"> AND title LIKE #{title} </if>
</trim>
<!-- 等價於 set (UPDATE 用) -->
<trim prefix="SET" suffixOverrides=",">
<if test="name != null"> name = #{name}, </if>
<if test="age != null"> age = #{age}, </if>
</trim>
屬性詳解:
prefix:前綴(如 WHERE、SET)prefixOverrides:移除前綴後的關鍵字(區分大小寫,需包含空格)suffix:後綴suffixOverrides:移除末尾字符(如 UPDATE 的逗號)類似 Java switch-case-default,只執行第一個匹配的 when。
<select id="getStudentListChoose" resultMap="studentResultMap" parameterType="StudentEntity">
SELECT * FROM STUDENT_TBL ST
<where>
<choose>
<when test="studentName != null and studentName != ''">
ST.STUDENT_NAME LIKE CONCAT('%', #{studentName}, '%')
</when>
<when test="studentSex != null">
AND ST.STUDENT_SEX = #{studentSex}
</when>
<when test="studentBirthday != null">
AND ST.STUDENT_BIRTHDAY = #{studentBirthday}
</when>
<otherwise>
1=1 -- 默認條件,防止 WHERE 後無內容
</otherwise>
</choose>
</where>
</select>
| 特性 | if | choose/when |
|---|---|---|
| 邏輯關係 | AND(全部匹配生效) | OR(優先匹配一個生效) |
| 適用場景 | 多條件組合篩選 | 互斥查詢方式(如:按ID/按名/按時間三選一) |
| 屬性 | 說明 | 示例值 |
|---|---|---|
| collection | 集合參數名(List->"list",Array->"array",Map->key名) | "list" / "ids" |
| item | 迭代變量名 | "id" / "item" |
| index | 索引變量名(可選) | "idx" |
| open | 開始字符 | "(" |
| separator | 分隔符 | "," |
| close | 結束字符 | ")" |
// 接口
List<Student> getByClassIdsArray(String[] classIds);
<select id="getByClassIdsArray" resultMap="studentResultMap">
SELECT * FROM STUDENT_TBL WHERE CLASS_ID IN
<foreach collection="array" item="cid" open="(" separator="," close=")">
#{cid}
</foreach>
</select>
// 接口
List<Student> getByClassIdsList(List<String> classIdList);
<foreach collection="list" item="cid" open="(" separator="," close=")">
#{cid}
</foreach>
// 接口
List<Blog> dynamicForeachTest(Map<String, Object> params);
<select id="dynamicForeachTest" resultType="Blog">
SELECT * FROM T_BLOG WHERE TITLE LIKE "%"#{title}"%"
AND ID IN
<foreach collection="ids" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</select>
Map<String, Object> params = new HashMap<>();
params.put("ids", Arrays.asList(1,2,3,6,7,9));
params.put("title", "中國");
mapper.dynamicForeachTest(params);
| 陷阱 | 現象 | 解決方案 |
|---|---|---|
| OGNL 中用 &&/|| | 配置解析報錯 | 必須用 and/or |
| where 標籤未生效 | SQL 語法錯誤 | 確保 where 內容非空;或改用 trim |
| foreach collection 錯誤 | 參數綁定失敗 | List用"list",Array用"array",Map用key名 |
| ${} 用於業務參數 | SQL 注入風險 | 業務參數必用 #{}, 只在表名/列名/排序用 ${} |
| IN 列表超限(>1000) | Oracle/MySQL 報錯 | 分批查詢或用臨時表/JOIN |
!= null and != '' 雙重檢查<sql> + <include> 復用條件、排序、列定義MyBatis 動態 SQL 通過 if、choose、where/trim、foreach、selectKey 五大核心標籤,配合 OGNL 表達式,提供了強大而優雅的 SQL 動態構建能力。掌握各標籤的適用場景、屬性配置、常見陷阱,能讓你編寫出既靈活又安全、既簡潔又高效的映射文件,是 MyBatis 進階開發的核心技能。