spring-data-jpa-extra:让 JPA 也能写动态 SQL,MyBatis 用户看了都沉默
Spring Data JPA 扩展库,401 star,支持模板化动态查询(Freemarker/Velocity),像 MyBatis 一样灵活写 SQL,同时保留 JPA 的简洁。
广告
spring-data-jpa-extra:让 JPA 也能写动态 SQL,MyBatis 用户看了都沉默
用 Spring Data JPA 的人一定有过这种纠结:写简单 CRUD 是真爽,一行代码搞定。但一旦遇到复杂查询、动态条件拼接,JPA 的 Specification 和 QueryDSL 就让人觉得还不如手写 SQL。spring-data-jpa-extra 这个库,就是想让你「鱼与熊掌兼得」——保留 JPA 的简洁,同时能像 MyBatis 一样灵活写动态 SQL。
项目背景
这是个 Java 项目,401 star,不算大火但实用性很强。作者的想法很直接:JPA 的 @Query 注解只能写静态 JPQL/SQL,动态条件不支持。而 MyBatis 的 XML 模板虽然灵活,但得维护一套 XML 文件。能不能把两者结合起来?于是就有了这个扩展——在 JPA 里引入模板引擎(Freemarker、Velocity),实现动态 SQL。
项目已经支持 Spring Boot 2+ 和 Spring 5+,master 分支维护还算活跃。
核心功能拆解
模板化动态查询。 这是核心能力。你可以在 resources 目录下放 .ftl(Freemarker)或 .vm(Velocity)模板文件,然后在 Repository 接口里引用。模板里可以写 if、foreach 这些逻辑,根据传入的参数动态拼接 SQL。比如一个用户搜索接口,用户名可选、时间范围可选、状态可选,用模板写比 Specification 优雅多了。
兼容 JPA 原生特性。 不是另起炉灶,而是扩展。你仍然可以用 JpaRepository 的所有方法,@Entity、@Table 这些注解也完全兼容。只是多了个 @TemplateQuery 注解,指定模板文件路径就行。对已有 JPA 项目的侵入性很小。
多模板引擎支持。 默认支持 Freemarker 和 Velocity,两种语法任选。Freemarker 功能更强,Velocity 更轻量。我试了下 Freemarker 版本,语法跟 MyBatis 的 XML 动态标签很像,上手很快。
分页和排序无缝对接。 返回类型可以是 Page、Slice、List,跟普通 JPA 查询完全一样。Spring Data 的分页参数(Pageable)直接传进去就行,不需要额外处理。
快速上手
Maven 依赖:
<dependency>
<groupId>com.slyak</groupId>
<artifactId>spring-data-jpa-extra</artifactId>
<version>3.0.0</version>
</dependency>
Repository 接口:
public interface UserRepository extends GenericJpaRepository<User, Long> {
@TemplateQuery
List<User> findByQuery(UserQuery query);
}
模板文件 resources/META-INF/user/UserRepository/findByQuery.ftl:
SELECT * FROM user WHERE 1=1
<#if query.name??>
AND name LIKE '%${query.name}%'
</#if>
<#if query.status??>
AND status = ${query.status}
</#if>
然后正常调用 userRepository.findByQuery(query) 就行。整个流程跟 MyBatis 几乎一样,但底层还是 JPA。
优缺点分析
优点:
- 动态 SQL 写法直观,比 Specification 和 Criteria API 简单太多
- 不破坏现有 JPA 项目结构,增量引入成本低
- 模板文件单独管理,SQL 集中存放,维护方便
- 支持主流模板引擎,选择灵活
- 分页排序原生支持,不用自己封装
缺点:
- 401 star,社区比较小,遇到问题可能搜不到解决方案
- 模板文件放 resources 里,项目大了之后文件管理有点乱
- 没有官方 Spring Boot Starter,需要自己配 Bean
- 错误提示不够友好,模板写错了报错信息比较模糊
- 跟 QueryDSL 比,类型安全没了,字段名写错要到运行时才暴露
跟同类产品比比
| 方案 | 动态 SQL | 类型安全 | 学习成本 | 侵入性 | 社区活跃度 |
|---|---|---|---|---|---|
| spring-data-jpa-extra | ✅ 模板 | ❌ | 低 | 低 | 低 |
| QueryDSL | ✅ DSL | ✅ | 中 | 中 | 高 |
| JPA Specification | ✅ API | ✅ | 高 | 低 | 高 |
| MyBatis | ✅ XML/注解 | ❌ | 低 | 高 | 极高 |
| jOOQ | ✅ DSL | ✅ | 中 | 中 | 中 |
跟 MyBatis 比,它的优势是不用维护一套独立的 ORM 体系,JPA 的缓存、关联映射这些还能继续用。跟 QueryDSL 比,它的优势是写动态 SQL 更直观,不用学一套 DSL 语法。但如果你的项目已经深度用了 QueryDSL,迁移过来意义不大。
适合谁用
三类场景比较合适:
- 已有 JPA 项目,偶尔需要复杂查询——不值得为了几个查询引入 MyBatis,用这个扩展刚好
- 团队熟悉 MyBatis 语法,想试 JPA——模板写法降低迁移门槛
- 中小型项目,不想引入 QueryDSL——QueryDSL 配置复杂,这个轻量很多
我实际用下来的感受是,这个库确实解决了 JPA 的一个真实痛点。但它的问题也很明显: star 数低意味着社区支持有限,生产环境用之前得自己把坑踩一遍。如果是核心系统的关键查询,我可能还是会选 QueryDSL 或者干脆上 MyBatis。但如果是内部工具、后台管理系统这种场景,用它完全够用了,而且省不少事。
关于作者
柳钉鱼,全栈开发者,GitHub 重度用户。过去 3 年 Star 了 900+ 仓库,这里只写我真正用过或深度调研过的工具。
📧 发现好工具想推荐?发邮件到 [email protected]
广告