重构动态 SQL(Dynamic SQL)的核心目标是:减少拼接错误、提升可读性、增强可维护性、防止 SQL 注入、方便测试。下面按「常见痛点 → 重构策略 → 示例」来说明。
"SELECT * FROM user WHERE 1=1 "
+ (name != null ? " AND name='" + name + "'" : "")
问题:易错、易注入、难维护。
✅ 防止 SQL 注入
✅ 数据库可缓存执行计划
Before
String sql = "SELECT * FROM user WHERE name = '" + name + "'";
After
String sql = "SELECT * FROM user WHERE name = ?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, name);
MyBatis 动态 SQL
<select id="queryUser">
SELECT * FROM user
<where>
<if test="name != null">
AND name = #{name}
</if>
<if test="age != null">
AND age = #{age}
</if>
</where>
</select>
✅ 优点:SQL 清晰、条件可组合
适合 复杂查询 / 多表 Join
UserQuery query = UserQuery.builder()
.name("Tom")
.age(20)
.build();
String sql = query.toSql();
Builder 内部:
Specification<User> spec = (root, query, cb) ->
cb.equal(root.get("name"), name);
QUser user = QUser.user;
queryFactory.selectFrom(user)
.where(user.name.eq(name))
.fetch();
✅ 编译期检查
✅ 可复用
✅ 易测试
推荐结构:
Controller
↓
Service
↓
Repository / Mapper
↓
SQL(XML / DSL)
❌ 不要在 Service 里拼 SQL
✅ SQL 只关心“数据怎么查”
-- 固定部分
SELECT u.id, u.name
FROM user u
-- 动态部分
WHERE 1=1
${dynamicConditions}
或更好方式:
✅ 是否全部参数化
✅ 是否有明显字符串拼接
✅ 是否能单测
✅ 是否可复用
✅ 是否数据库无关
✅ 新人能否看懂
| 维度 | 旧写法 | 重构后 |
|---|---|---|
| 安全性 | ❌ | ✅ |
| 可读性 | ❌ | ✅ |
| 可维护性 | ❌ | ✅ |
| 测试性 | ❌ | ✅ |
如果你愿意,可以:
我可以帮你直接重构成可落地的版本。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。