“手写 Dynamic SQL”通常指不依赖 ORM 全自动生成 SQL,而是根据条件在代码中动态拼接 / 构造 SQL 语句。下面从思路、常见方式、示例、注意事项几个方面讲清楚。
Dynamic SQL = SQL 不是写死的,而是根据运行时的条件变化
常见变化点:
String sql = "SELECT * FROM user WHERE 1=1";
if (name != null) {
sql += " AND name = '" + name + "'";
}
❌ 问题:
✅ 安全、标准、可控
StringBuilder sql = new StringBuilder("SELECT * FROM user WHERE 1=1");
List<Object> params = new ArrayList<>();
if (name != null) {
sql.append(" AND name = ?");
params.add(name);
}
if (age != null) {
sql.append(" AND age > ?");
params.add(age);
}
sql.append(" ORDER BY id DESC");
PreparedStatement ps = conn.prepareStatement(sql.toString());
for (int i = 0; i < params.size(); i++) {
ps.setObject(i + 1, params.get(i));
}
✅ 优点:
<select id="queryUser" parameterType="map">
SELECT * FROM user
<where>
<if test="name != null">
AND name = #{name}
</if>
<if test="age != null">
AND age > #{age}
</if>
</where>
</select>
@SelectProvider(type = UserSqlBuilder.class, method = "buildQuery")
List<User> query(UserQuery q);
public class UserSqlBuilder {
public String buildQuery(UserQuery q) {
return new SQL() {{
SELECT("*");
FROM("user");
if (q.getName() != null) WHERE("name = #{name}");
if (q.getAge() != null) WHERE("age > #{age}");
}}.toString();
}
}
如:
SQL 类示例(MyBatis SQL 类):
new SQL()
.SELECT("*")
.FROM("user")
.WHERE("status = 1")
.ORDER_BY("create_time DESC")
.toString();
WHERE 1=1 或 <where>避免第一个条件前多一个 AND
? 或 #{}❌ 不要直接拼变量
if (ids != null && !ids.isEmpty()) {
sql.append(" AND id IN (");
sql.append(ids.stream().map(i -> "?").collect(Collectors.joining(",")));
sql.append(")");
params.addAll(ids);
}
Set<String> allow = Set.of("id", "name", "age");
if (allow.contains(sortField)) {
sql.append(" ORDER BY ").append(sortField);
}
❌ SQL 注入
❌ 字符串拼接引号错误
❌ 忘记参数顺序
❌ ORDER BY 直接拼用户输入
❌ 动态 SQL 太复杂,难以维护
✅ 报表查询
✅ 多条件筛选
✅ 复杂业务 SQL
❌ 简单 CRUD(用 ORM 更好)
如果你愿意,可以告诉我:
我可以直接帮你写一个完整可用的 Dynamic SQL 示例。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。