问题背景
在医学指南管理系统项目中,需要实现中英文临床指南的多条件检索:按科室、疾病类型、发布时间、关键词等多维度筛选。传统 MyBatis XML 方式写动态 SQL 会导致 XML 文件膨胀,难以维护。
为什么选 MyBatis Dynamic SQL
MyBatis Dynamic SQL 是 MyBatis 官方推出的 Java DSL 风格的 SQL 构建库,优势在于:
- 类型安全,编译期检查
- 无需 XML 配置文件
- 方法链式调用,可读性好
- 自动规避 SQL 注入风险
核心实现
依赖配置
<dependency>
<groupId>org.mybatis.dynamic-sql</groupId>
<artifactId>mybatis-dynamic-sql</artifactId>
<version>1.5.0</version>
</dependency>
多条件检索
public List<Guideline> searchGuidelines(SearchDTO dto) {
SelectStatementProvider select = select(
id, title, department, publishDate, language
)
.from(guidelineTable)
.where(id, isNotNull())
.and(title, isLike("%" + dto.getKeyword() + "%")
.filter(ks -> StringUtils.hasText(dto.getKeyword())))
.and(department, isEqualTo(dto.getDepartment())
.filter(ds -> StringUtils.hasText(dto.getDepartment())))
.and(language, isEqualTo(dto.getLanguage())
.filter(ls -> StringUtils.hasText(dto.getLanguage())))
.orderBy(publishDate.descending())
.build()
.render(RenderingStrategies.MYBATIS3);
return client.selectMany(select);
}
.filter() 方法是关键:只有当条件成立时,对应的 WHERE 子句才会被拼入 SQL,相当于 XML 中的 <if test="...">。
踩坑记录
坑 1:LIKE 查询的百分号位置
MyBatis Dynamic SQL 的 isLike 不会自动添加 %,需要手动拼接。建议封装工具方法。
坑 2:IN 查询的参数绑定
使用 isIn 时,空集合会导致 SQL 语法错误。务必在调用前检查集合是否为空:
.and(id, isIn(dto.getIds())
.filter(ids -> ids != null && !ids.isEmpty()))
坑 3:FULLTEXT 全文索引的使用
对于文章标题和正文的全文搜索,使用 MySQL FULLTEXT 索引比 LIKE 快 10 倍以上:
ALTER TABLE guideline ADD FULLTEXT INDEX ft_title_content (title, content);
总结
MyBatis Dynamic SQL 总体来说是一个优秀的库,类型安全的 DSL 确实比 XML 维护性好很多。但在复杂关联查询场景下,XML 的可读性可能更好——关键是根据场景选择合适的工具。