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

MyBatis 動態 SQL 完全指南:if/choose/trim/foreach/bind 實戰與最佳實踐

     編輯:Java 綜合教學

告別字符串拼接 SQL:掌握 MyBatis 強大的動態 SQL 語言構建靈活、安全、可維護的查詢

動態 SQL 是 MyBatis 最核心、最實用的特性。本文系統講解 if、choose/when/otherwise、trim/where/set、foreach、bind 五大核心標簽,結合實戰 XML Mapper 示例,展示條件查詢、動態更新、批量插入、IN 條件構建等高頻場景,並給出演示項目完整代碼結構。

一、 核心標簽速查表

標簽用途關鍵屬性
<if>條件包含 SQL 片段test="OGNL 表達式"
<choose> <when> <otherwise>互斥分支選擇 (類似 switch)test 依次判斷,otherwise 兜底
<where>智能 WHERE 子句:自動去除首個 AND/OR、補全 WHERE 關鍵字無屬性
<trim>通用字符串修剪:prefix/suffix/prefixOverrides/suffixOverrides極其靈活,可模擬 where/set
<set>智能 SET 子句:自動去除尾部逗號、補全 SET 關鍵字無屬性
<foreach>集合遍歷構建 IN 列表、批量 VALUES、UNION ALL 等collection/item/index/open/separator/close
<bind>OGNL 表達式結果綁定為變量,供後續引用name/value

二、 實戰場景與代碼示例

1. 條件查詢:<where> + <if>

<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>

效果:若所有條件為 null → SELECT * FROM BLOG;若只有 title → SELECT * FROM BLOG WHERE title LIKE ? (自動去除 AND)。

2. 排他分支:<choose>

<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>

3. 動態更新:<set> + <if>

<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>

效果:只更新非 null 字段,自動處理逗號,避免 SET username=?, password=?, 尾逗號語法錯誤。

4. 批量插入 / IN 條件:<foreach>

-- 批量插入 (Oracle dual + UNION ALL)
<insert id="svaeTalentTypeBatch" parameterType="list">
    INSERT INTO APP_ZONE_USER_TALENT_TYPE (ID, TALENT_ID, TYPE_CODE)
    SELECT SEQ_TALENT_TYPE_ID.NEXTVAL, t.* FROM (
        <foreach collection="list" item="item" index="index" separator="UNION ALL">
            SELECT #{item.talentId}, #{item.typeCode} FROM DUAL
        </foreach>
    ) t
</insert>

-- IN 條件查詢
<select id="selectPostIn" resultType="Post">
    SELECT * FROM POST WHERE ID IN
    <foreach collection="list" item="item" index="index" open="(" separator="," close=")">
        #{item}
    </foreach>
</select>

-- 批量刪除
<delete id="delDetailType">
    DELETE FROM APP_ZONE_USER_TALENT_TYPE WHERE ID IN
    <foreach collection="ids" item="item" open="(" separator="," close=")">
        #{item}
    </foreach>
</delete>

5. 綁定變量:<bind> 簡化複雜表達式

<select id="selectBlogsLike" resultType="Blog">
    <bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
    SELECT * FROM BLOG WHERE title LIKE #{pattern}
</select>

三、 進階特性:多数據庫支持與腳本語言擴展

  • _databaseId 變量:配置 databaseIdProvider 後,動態 SQL 可用 _databaseId 區分方言 (Oracle/DB2/MySQL),構建特定序列/分頁/鎖語句。
  • 可插拔腳本語言:實現 LanguageDriver 接口,配置 defaultScriptingLanguage 或方法級 @Lang,支持 Velocity、Freemarker、Groovy 等模板引擎編寫動態 SQL。

四、 完整項目代碼結構參考

Mapper XML (含 ResultMap、批量操作、動態更新、條件查詢):

<mapper namespace="cn.ffcs.zone.detailType.persistent.DetailTypeMapper">
    <resultMap id="BaseResultMap" type="DetailType"> ... </resultMap>
    <select id="findDetailTypes" resultMap="BaseResultMap"> ... </select>
    <insert id="saveEntity"> <selectKey .../> INSERT ... </insert>
    <insert id="svaeTalentTypeBatch" parameterType="list"> ... <foreach .../> ... </insert>
    <delete id="delDetailType"> ... <foreach .../> ... </delete>
</mapper>

Mapper 接口:

public interface UserCardMapper extends BaseMapper<UserCard> {
    int saveUserCard(UserCard uc);
    @Select("SELECT * FROM app_zone_user_card WHERE user_id=#{userId}")
    @ResultMap("BaseResultMap") UserCard findByUserId(@Param("userId") Long userId);
    // ... 其他查詢/更新方法
    List<UserCard> findByParam(Map<String, Object> param); // 通用條件查詢
}

BaseMapper:定義通用 CRUD + 分頁查詢契約。

五、 最佳實踐總結

  1. 優先用 <where>/<set>:自動處理關鍵字與 AND/OR/逗號,減少手動拼接錯誤。
  2. <foreach> 批量操作:單條 SQL 完成批量 INSERT/DELETE/IN,性能遠超循環調用。
  3. OGNL 表達式安全:test="@Ognl@isNotNull(x)" 避免空指針;複雜邏輯用 <bind> 提取變量提升可讀性。
  4. 參數類型明確:#{prop,jdbcType=VARCHAR} 指定 JDBC 類型,避免類型推斷失敗 (尤其 Oracle/PostgreSQL)。
  5. SQL 片段復用:<sql id="cols">...</sql> + <include refid="cols"/> 減少重複。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved