首页 >文档 > mybatis动态sql示例

mybatis动态sql示例

掌握MyBatis动态SQL是Java面试必考重点!本文深度解析MyBatis动态SQL核心标签的实战用法,包括条件查询的<where>与<if>标签、分支选择的<choose>标签、批量操作的<foreach>标签、选择性更新的<set>标签以及代码复用的<sql>标签。通过真实面试场景案例,教你如何避免WHERE 1=1、处理多条件查询、实现批量操作等高频考点问题。附赠2025年最新Java面试宝典下载链接,助你轻松应对MyBatis相关面试问题,提升开发效率与代码质量。

好的,程序员朋友,咱们直奔主题。面试中MyBatis的动态SQL绝对是高频考点,不会灵活运用它,写起复杂查询那叫一个头疼。今天就结合真实面试场景,给你掰开了揉碎了讲讲MyBatis动态SQL的那些核心用法,助你面试一臂之力!

📁 先送上干货!2025年Java面试宝典(含MyBatis及更多深度内容): 链接: https://pan.baidu.com/s/1RUVf75gmDVsg8MQp4yRChg?pwd=9b3g 提取码: 9b3g 记得保存好,面试复习神器!


深入浅出:MyBatis动态SQL实战精讲 (面试高频点!)

刚面完一个三年经验的Java工程师,问到MyBatis动态SQL时,他卡在了如何根据多个条件灵活组合查询上。这不稀奇,很多朋友对这部分的理解停留在会写<if>标签,但一到复杂场景就懵。今天,我就以几个典型的面试问题为引子,带你真正吃透MyBatis动态SQL的精髓。

场景一:条件不确定?巧用 <if><where>

面试官:“现在有个用户查询需求,前端可能传用户名、状态、注册时间范围等多个条件,但这些条件不是每次都有值,后端接口你怎么设计?MyBatis这块SQL怎么写?”

关键点:避免WHERE 1=1!

老式做法可能是WHERE 1=1 AND username=#{name}...,但这既不优雅也有SQL注入隐患(虽然MyBatis用了#{}防注入,但1=1没必要)。MyBatis动态SQL<where>标签就是干这个的!

<select id="findUsers" resultType="User">
    SELECT * FROM user
    <where>
        <if test="username != null and username != ''">
            AND username LIKE CONCAT('%', #{username}, '%')
        </if>
        <if test="status != null">
            AND status = #{status}
        </if>
        <if test="startTime != null">
            AND register_time >= #{startTime}
        </if>
        <if test="endTime != null">
            AND register_time <= #{endTime}
        </if>
    </where>
</select>

面试回答要点:

  1. 明确使用<where>标签包裹条件,它的智能之处在于:
    • 只有当里面的<if>条件成立时,才会插入WHERE关键字。
    • 会自动去除第一个条件前的AND(或OR)。上面例子中,如果只有status条件成立,生成的SQL是WHERE status = ?,没有多余的AND
  2. <if>标签的test属性写的是OGNL表达式,判断条件是否成立。注意空字符串的判断!
  3. 强调避免了WHERE 1=1这种不规范的写法。

场景二:多选一?<choose> <when> <otherwise> 上阵

面试官:“现在查询订单,要求根据传入的sortType值(1按时间倒序,2按金额倒序,3按更新时间倒序,其他情况按ID倒序)进行排序,怎么写?”

关键点:实现分支选择逻辑

这就是典型的Switch-Case场景,MyBatis动态SQL<choose>家族搞定。

<select id="findOrders" resultType="Order">
    SELECT * FROM order
    <where>
        ... (其他查询条件)
    </where>
    ORDER BY
    <choose>
        <when test="sortType == 1">
            create_time DESC
        </when>
        <when test="sortType == 2">
            total_amount DESC
        </when>
        <when test="sortType == 3">
            update_time DESC
        </when>
        <otherwise>
            id DESC
        </otherwise>
    </choose>
</select>

面试回答要点:

  1. <choose>包裹整个分支逻辑。
  2. <when>相当于casetest属性判断是否匹配。
  3. <otherwise>相当于default,所有when都不匹配时执行。
  4. 注意ORDER BY后面直接跟<choose>,结构清晰。

场景三:批量操作利器:<foreach> 循环

面试官:“如何实现根据传入的一组用户ID(List)批量删除用户?”

关键点:拼接IN语句或批量INSERT/UPDATE

批量操作是MyBatis动态SQL的强项,<foreach>闪亮登场。

<!-- 批量删除 -->
<delete id="deleteUsersByIds">
    DELETE FROM user WHERE id IN
    <foreach item="id" collection="list" open="(" separator="," close=")">
        #{id}
    </foreach>
</delete>

<!-- 批量插入 (假设有User列表) -->
<insert id="batchInsertUsers">
    INSERT INTO user (username, email) VALUES
    <foreach item="user" collection="list" separator=",">
        (#{user.username}, #{user.email})
    </foreach>
</insert>

面试回答要点:

  1. <foreach>核心属性:
    • collection: 传入的集合参数名(如list, array, 或Map/对象里的属性名)。
    • item: 循环中当前元素的别名。
    • index (可选): 当前元素的索引或Map的key。
    • open/close: 循环开始/结束时添加的字符串。
    • separator: 每次循环之间的分隔符。
  2. 批量删除:核心是拼接IN (id1, id2, ...),用open="(", close=")", separator=","
  3. 批量插入:拼接VALUES (..), (..), (..),注意separator=","放在值后面。
  4. 强调#{}防止SQL注入。

场景四:灵活更新:<set><if>

面试官:“更新用户信息,可能只更新邮箱,或只更新状态,或两者都更新,怎么避免全字段更新?”

关键点:避免全字段更新,只SET有变化的字段

这就要用到MyBatis动态SQL<set>标签,它和<where>类似,智能处理SET和逗号。

<update id="updateUserSelective">
    UPDATE user
    <set>
        <if test="email != null and email != ''">
            email = #{email},
        </if>
        <if test="status != null">
            status = #{status},
        </if>
        <if test="avatar != null">
            avatar = #{avatar},
        </if>
    </set>
    WHERE id = #{id}
</update>

面试回答要点:

  1. 使用<set>标签包裹要更新的字段。
  2. <set>标签的智能之处:
    • 只有里面<if>条件成立时,才会插入SET关键字。
    • 会自动去除最后一个条件后的逗号。比如只更新status,生成的SQL是UPDATE user SET status = ? WHERE ...,没有多余的逗号。
  3. 强调这是实现“选择性更新”的标准做法。

场景五:复用代码块:<sql><include>

面试官:“多个查询映射文件中都需要用到相同的用户基础字段列表,怎么避免重复定义?”

关键点:代码复用,提高可维护性

MyBatis动态SQL提供了代码片段定义和引用的能力。

<!-- 定义可复用的列名片段 -->
<sql id="userBaseColumns">
    id, username, email, status, create_time
</sql>

<!-- 在其他查询中引用 -->
<select id="selectUserById" resultType="User">
    SELECT
    <include refid="userBaseColumns"/>
    FROM user WHERE id = #{id}
</select>

<select id="findActiveUsers" resultType="User">
    SELECT
    <include refid="userBaseColumns"/>
    FROM user WHERE status = 'ACTIVE'
</select>

面试回答要点:

  1. 使用<sql id="xxx">定义一个可复用的SQL片段。
  2. 在需要的地方使用<include refid="xxx"/>引入该片段。
  3. 强调这样做的好处是:一处修改,多处生效,减少冗余,方便维护。

💡 面试实战小贴士:

  • 面试官问MyBatis动态SQL,基本就是想考察你对<if>, <where>, <set>, <foreach>, <choose>这些核心标签的掌握程度和实际应用场景。
  • 一定要结合具体业务场景举例说明,比如“我在XX项目里,实现XX功能时,用了XX标签来解决XX问题”。
  • 明确说出标签的作用和解决的问题(如避免WHERE 1=1、避免多余逗号、实现分支选择、高效处理批量操作)。
  • 提到使用#{}防止SQL注入是加分项。

🎁 福利时间:备考冲刺利器!

如果你正在准备面试,需要开通【面试鸭】会员获取海量真题和深度解析,别忘了走专属福利通道!通过 面试鸭返利网 购买会员,立享25元返利! 实实在在的优惠,助你高效备战。

面试鸭返利网 通过面试鸭返利网购买,返利25元

![面试鸭返利网](

如果你想获取更多关于面试鸭的优惠信息,可以访问面试鸭返利网面试鸭优惠网,了解最新的优惠活动和返利政策。

🎯 立即加入面试鸭会员 →

支付宝扫码领取1-8元无门槛红包

支付宝红包二维码