动态SQL
动态SQL是MyBatis最强大的特性之一,它允许你根据条件动态拼接SQL语句,解决传统JDBC中大量拼接字符串的繁琐问题。
1. 什么是动态SQL?
动态SQL是一种根据运行时条件动态生成和执行SQL语句的技术。与静态SQL(在代码中固定写死的SQL)不同,动态SQL允许程序根据不同输入或条件动态灵活构建SQL,适用于需要灵活查询、参数化条件或复杂业务逻辑的场景。
- 核心特点:通过条件判断、循环等逻辑,灵活拼接SQL字段,避免硬编码复杂的查询或更新逻辑。
- 典型场景:多条件查询、批量操作、动态字段更新等。
2. 动态SQL的作用
- 灵活适配业务需求:根据参数动态生成不同的SQL,避免写多个重复的静态SQL。
- 减少代码冗余:通过逻辑控制标签(如if、foreach)简化代码。
- 提升可维护性:集中管理SQL逻辑,修改时只需调整XML或模板文件。
- 防止SQL注入:结合参数化查询(#{ }),避免直接拼接字符串的风险。
3. 动态SQL的常用标签
1. <if>标签:条件判断
作用:根据表达式的值(true/false)决定是否包含标签内的内容。
示例:根据传入参数动态更新字段。
<update id="updateUser">
UPDATE user
SET
<if test="name != null">name = #{name},</if>
<if test="age != null">age = #{age},</if>
<if test="email != null">email = #{email}</if>
WHERE id = #{id}
</update>
风险点:如果最后一个<if>条件不满足,SQL末尾会多一个逗号,导致语法错误!
错误SQL:
UPDATE user SET name = 'John', WHERE id = 1; -- 逗号多余
2. <set>标签:动态更新字段(自动处理逗号)
作用:专用于处理UPDATE语句,自动去除SET子句末尾多余的逗号。
修正后的安全写法:
<update id="updateUser">
UPDATE user
<set>
<if test="name != null">name = #{name},</if>
<if test="age != null">age = #{age},</if>
<if test="email != null">email = #{email},</if>
</set>
WHERE id = #{id}
</update>
MyBatis会智能生成:
-- 当只有 name 和 age 有值时
UPDATE user SET name = 'John', age = 25 WHERE id = 1;
3. <trim>标签:自定义字符串处理(自定义修剪SQL片段的前缀、后缀)
作用:更灵活地处理前后缀,可替代<set>或<where>。
示例:用<trim>实现<set>的效果:
<trim prefix="SET" suffixOverrides=",">
<if test="name != null">name = #{name},</if>
<if test="age != null">age = #{age},</if>
</trim>
等同于<set>,但可以自定义前缀和要删除的后缀。
- 属性及作用:
- prefix:添加前缀
- suffix:添加后缀
- prefixOverride:去除开头匹配的字符串
- suffixOverride:去除结尾匹配的字符串
4. <where>标签:智能处理where子句
作用:自动去除WHERE后的首个AND或OR,避免语法错误。
错误场景:
<select id="findUser">
SELECT * FROM user
WHERE
<if test="name != null">AND name = #{name}</if>
<if test="age != null">AND age = #{age}</if>
</select>
若所有条件都不满足,生成的SQL是:SELECT * FROM user WHERE (语法错误)。
修正后:
<select id="findUser">
SELECT * FROM user
<where>
<if test="name != null">AND name = #{name}</if>
<if test="age != null">AND age = #{age}</if>
</where>
</select>
MyBatis会处理成:SELECT * FROM user WHERE name = 'John' 或直接去掉WHERE。
5. <foreach>标签:遍历集合或数组
作用:常用于IN查询或批量插入。
5.1 批量新增(List集合)
示例:根据id列表查询用户:
<insert id="batchInsert">
INSERT INTO user (name, age) VALUES
<foreach collection="list" item="user" separator=",">
(#{user.name}, #{user.age})
</foreach>
</insert>
生成SQL:select * from user where id in(1,2,3)
-
参数说明:
- collection="list":集合参数名(若参数是List类型,默认名为list)
- item:遍历时的元素别名
- separator:元素间的分隔符
5.2 批量删除(数组)
<delete id="batchDelete">
DELETE FROM user WHERE id IN
<foreach collection="array" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
-
参数说明:
- collection="array":数组参数默认名为array。
- open/close:包裹遍历结果的前后缀。
6. <choose>标签:
作用:实现多条件分支逻辑(类似switch-case)
<select id="findUser" resultType="User">
SELECT * FROM user
<where>
<choose>
<when test="name != null">
name = #{name}
</when>
<when test="email != null">
email = #{email}
</when>
<otherwise>
status = 'ACTIVE'
</otherwise>
</choose>
</where>
</select>