**动态 SQL(Dynamic SQL)**通常指根据运行时的条件拼接或生成不同的 SQL 语句(如 MyBatis 的 <if>、<foreach>,或 Java/Python 中字符串拼接 SQL)。其“最佳实践”核心目标是:安全、可维护、可调试、性能可控。
下面从原则、写法、框架示例和常见坑四个层面说明。
❌ 错误:
String sql = "SELECT * FROM user WHERE name = '" + name + "'";
✅ 正确:使用参数化查询(PreparedStatement / 占位符)
不要手写复杂拼接逻辑:
<if> <choose> <foreach> <where>Criteria API、Specification只让条件动态,结构尽量静态:
排序、分组、字段名不能参数化时:
Set<String> allowColumns = Set.of("id", "name", "create_time");
if (!allowColumns.contains(sortField)) {
sortField = "id";
}
<where> + <if>(最常用)<select id="listUser" resultType="User">
SELECT * FROM user
<where>
<if test="name != null">
AND name LIKE CONCAT('%', #{name}, '%')
</if>
<if test="status != null">
AND status = #{status}
</if>
</where>
</select>
✅ <where> 自动处理多余 AND
<foreach> 用于 IN 查询AND id IN
<foreach collection="ids" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
<choose> 替代 if-else<choose>
<when test="type == 'A'">AND type = 'A'</when>
<when test="type == 'B'">AND type = 'B'</when>
<otherwise>AND type = 'C'</otherwise>
</choose>
Specification<User> spec = (root, query, cb) -> {
List<Predicate> list = new ArrayList<>();
if (name != null) list.add(cb.like(root.get("name"), name));
return cb.and(list.toArray(new Predicate[0]));
};
✅ 类型安全
✅ 不易出错
✅ 可组合
❌ 所有字段都可变
✅ 固定主结构 + 动态条件
logImpl=STDOUT动态 SQL 不应变成“SQL 生成器”,复杂逻辑建议:
| 反模式 | 问题 |
|---|---|
| 字符串拼接 SQL | SQL 注入 |
| 动态 ORDER BY 无白名单 | 注入风险 |
| 动态表名无校验 | 结构风险 |
| 超复杂动态 SQL | 难维护 |
| 拼接后不打印 SQL | 难调试 |
动态 SQL 的最佳实践:结构静态、条件动态、参数化查询、白名单控制、框架优先。
如果你指的是某种具体技术(MyBatis / JPA / Python / Go)或某种场景(报表 / 搜索 / 权限过滤),我可以给更针对性的示例。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。