好的,程序员朋友,咱们直奔主题。面试中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>
面试回答要点:
- 明确使用
<where>标签包裹条件,它的智能之处在于:- 只有当里面的
<if>条件成立时,才会插入WHERE关键字。 - 会自动去除第一个条件前的
AND(或OR)。上面例子中,如果只有status条件成立,生成的SQL是WHERE status = ?,没有多余的AND。
- 只有当里面的
<if>标签的test属性写的是OGNL表达式,判断条件是否成立。注意空字符串的判断!- 强调避免了
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>
面试回答要点:
<choose>包裹整个分支逻辑。<when>相当于case,test属性判断是否匹配。<otherwise>相当于default,所有when都不匹配时执行。- 注意
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>
面试回答要点:
<foreach>核心属性:collection: 传入的集合参数名(如list,array, 或Map/对象里的属性名)。item: 循环中当前元素的别名。index(可选): 当前元素的索引或Map的key。open/close: 循环开始/结束时添加的字符串。separator: 每次循环之间的分隔符。
- 批量删除:核心是拼接
IN (id1, id2, ...),用open="(",close=")",separator=","。 - 批量插入:拼接
VALUES (..), (..), (..),注意separator=","放在值后面。 - 强调
#{}防止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>
面试回答要点:
- 使用
<set>标签包裹要更新的字段。 <set>标签的智能之处:- 只有里面
<if>条件成立时,才会插入SET关键字。 - 会自动去除最后一个条件后的逗号。比如只更新
status,生成的SQL是UPDATE user SET status = ? WHERE ...,没有多余的逗号。
- 只有里面
- 强调这是实现“选择性更新”的标准做法。
场景五:复用代码块:<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>
面试回答要点:
- 使用
<sql id="xxx">定义一个可复用的SQL片段。 - 在需要的地方使用
<include refid="xxx"/>引入该片段。 - 强调这样做的好处是:一处修改,多处生效,减少冗余,方便维护。
💡 面试实战小贴士:
- 面试官问MyBatis动态SQL,基本就是想考察你对
<if>,<where>,<set>,<foreach>,<choose>这些核心标签的掌握程度和实际应用场景。 - 一定要结合具体业务场景举例说明,比如“我在XX项目里,实现XX功能时,用了XX标签来解决XX问题”。
- 明确说出标签的作用和解决的问题(如避免WHERE 1=1、避免多余逗号、实现分支选择、高效处理批量操作)。
- 提到使用
#{}防止SQL注入是加分项。
🎁 福利时间:备考冲刺利器!
如果你正在准备面试,需要开通【面试鸭】会员获取海量真题和深度解析,别忘了走专属福利通道!通过 面试鸭返利网 购买会员,立享25元返利! 实实在在的优惠,助你高效备战。
通过面试鸭返利网购买,返利25元


