Java MyBatis 如何写动态 SQL
在日常开发中,我们常遇到这样的场景:做一个用户查询功能,用户可能只填了姓名,可能只填了手机号,也可能两个都填,要是用固定的SQL,就得写好几个版本,特别麻烦。这时候就需要用到MyBatis的动态SQL,它就像一个“会看菜单点菜”的小助手,能根据不同条件自动调整SQL语句,不用我们重复写代码。
什么是MyBatis动态SQL?
很多人第一次接触会觉得“动态SQL”是复杂的技术,其实换个生活化的例子就好懂:比如你去奶茶店点单,“少糖、加珍珠、常温”是你的个性化要求,店员不会给你做固定甜度的茶,而是根据你的需求调整配料——这和动态SQL的逻辑一模一样。MyBatis的动态SQL,就是让SQL能根据Java代码里的条件变化,自动拼接成合适的语句,不用手动写多套重复代码,既省时间又不容易出错。

常用的动态SQL写法(附生活化例子)
MyBatis里的动态SQL靠特定标签实现,都是贴近日常逻辑的规则,不用死记硬背,跟着例子练两次就会。
`<if>` 标签:满足条件才加内容
<if>是最常用的标签,相当于“只有满足XX条件,才加这部分内容”。比如要写用户查询,Java里传了username和phone两个参数,我们想:如果username不为空,才加“姓名模糊匹配”的条件。
举个具体的Mapper示例:
`xml
<select id="queryUser" resultType="User">
SELECT * FROM user WHERE 1=1
<if test="username != null and username != ''">
AND username LIKE CONCAT('%', #{username}, '%')
</if>
<if test="phone != null and phone != ''">
AND phone = #{phone}
</if>
</select>
`
这里特意加了WHERE 1=1,是为了让后面的AND不会出错——要是没有这个,第一个条件为空时,SQL会变成SELECT * FROM user WHERE AND phone=...,语法就错了,这是新手容易踩的小坑。
`<where>` 标签:自动处理多余的AND/OR
刚才的WHERE 1=1是临时方案,MyBatis有更优雅的解决办法:<where>标签,它会自动帮你处理开头多余的AND或OR。把上面的代码改一下:
`xml
<select id="queryUser" resultType="User">
SELECT * FROM user
<where>
<if test="username != null and username != ''">
AND username LIKE CONCAT('%', #{username}, '%')
</if>
<if test="phone != null and phone != ''">
AND phone = #{phone}
</if>
</where>
</select>
`
这样如果两个if都不满足,<where>会自动忽略整个条件块,SQL就变成SELECT * FROM user,不会有多余的语法错误,是不是很省心?
`<foreach>` 标签:批量处理集合
如果需要按ID列表查询用户,比如要查ID是1、3、5的三个用户,这时候要把ID列表拆成(1,3,5)的形式,用<foreach>标签就能轻松搞定,相当于“把集合里的每个元素都循环处理,拼成需要的内容”。示例:
`xml
<select id="queryUserByIds" resultType="User">
SELECT * FROM user WHERE id IN
<foreach collection="idList" item="id" open="(" separator="," close=")">
{id}
</foreach>
</select>
`
这里的参数idList是Java里传的集合,<foreach>会自动把它转成(1,3,5),最终SQL就是SELECT * FROM user WHERE id IN (1,3,5),完美适配批量查询的需求。
新手容易忽略的小细节
动态SQL虽然好用,但有两个小细节要注意:一是参数的非空判断,不能只判断username != null,还要判断username != '',避免空字符串也被当成有效条件;二是collection属性要对应Java里的参数类型,传的是List就写list,传的是Map里的集合就写对应的key,写错了会报错。
学会这几个常用的动态SQL写法,就能解决80%以上的业务场景,不用再为写多套固定SQL头疼,开发效率能提升不少。