掌握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 记得保存好,面试复习神器!
刚面完一个三年经验的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"/>引入该片段。💡 面试实战小贴士:
<if>, <where>, <set>, <foreach>, <choose>这些核心标签的掌握程度和实际应用场景。#{}防止SQL注入是加分项。🎁 福利时间:备考冲刺利器!
如果你正在准备面试,需要开通【面试鸭】会员获取海量真题和深度解析,别忘了走专属福利通道!通过 面试鸭返利网 购买会员,立享25元返利! 实实在在的优惠,助你高效备战。
通过面试鸭返利网购买,返利25元


面试鸭小程序码

美团大额优惠券,给自己加个鸡腿吧!

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