动态 SQL 主要用于SQL 语句的结构或条件在运行时才能确定的场景,常见于业务复杂、查询条件不固定、对象结构可变等情况。下面按典型场景 + 示例说明来总结。
场景特点:
查询条件由用户选择,可能传、也可能不传。
示例:
用户查询订单,可选条件:
SQL 示例(MyBatis):
<select id="queryOrders" resultType="Order">
SELECT * FROM orders
<where>
<if test="orderNo != null">
AND order_no = #{orderNo}
</if>
<if test="userId != null">
AND user_id = #{userId}
</if>
<if test="status != null">
AND status = #{status}
</if>
<if test="startTime != null">
AND create_time >= #{startTime}
</if>
</where>
</select>
✅ 避免写大量 if-else 拼接 SQL
场景特点:
排序字段、排序方式由前端或参数决定。
示例:
<select id="queryUsers">
SELECT * FROM user
ORDER BY
<choose>
<when test="sortBy == 'age'">age</when>
<when test="sortBy == 'name'">name</when>
<otherwise>id</otherwise>
</choose>
<if test="order == 'desc'">DESC</if>
</select>
场景特点:
只更新用户传过来的字段,不更新 null 字段。
示例:
<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>
✅ 避免把字段更新成 null
场景特点:
插入字段不固定,比如不同业务类型字段不同。
示例:
<insert id="insertUser">
INSERT INTO user
<trim prefix="(" suffix=")" suffixOverrides=",">
id,
<if test="name != null">name,</if>
<if test="age != null">age,</if>
</trim>
VALUES
<trim prefix="(" suffix=")" suffixOverrides=",">
#{id},
<if test="name != null">#{name},</if>
<if test="age != null">#{age},</if>
</trim>
</insert>
场景特点:
ID 列表、状态列表等动态变化。
示例:
<select id="queryByIds">
SELECT * FROM user
WHERE id IN
<foreach collection="ids" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</select>
场景特点:
表名、库名在运行时决定。
示例:
<select id="queryLog">
SELECT * FROM log_${tableSuffix}
WHERE id = #{id}
</select>
⚠️ 注意:${} 有 SQL 注入风险,需严格校验参数
场景特点:
是否连表由条件决定。
示例:
SELECT u.*
FROM user u
<if test="needOrder">
LEFT JOIN orders o ON u.id = o.user_id
</if>
场景特点:
根据用户角色、部门动态拼接条件。
示例:
<if test="role == 'MANAGER'">
AND department_id = #{departmentId}
</if>
<if test="role == 'ADMIN'">
<!-- 不限制 -->
</if>
❌ 不推荐场景:
${}(SQL 注入)| 框架 | 动态 SQL 方式 |
|---|---|
| MyBatis | XML / 注解 <if> <foreach> |
| JPA / Hibernate | Criteria API、Specification |
| Spring JDBC | 手动拼接(不推荐) |
| MyBatis-Plus | Lambda / Wrapper |
只要 SQL 的“条件、字段、表名、结构”在运行时才能确定,就适合用动态 SQL。
如果你愿意,我可以:
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。