spring-data-jpa-extra: Dynamic SQL in JPA, MyBatis Users Would Be Jealous
Spring Data JPA extension with 401 stars. Template-based dynamic queries via Freemarker/Velocity — flexible SQL like MyBatis while keeping JPA's simplicity.
广告
spring-data-jpa-extra: Dynamic SQL in JPA, MyBatis Users Would Be Jealous
If you’ve used Spring Data JPA, you know the struggle. Simple CRUD is beautiful — one-liners everywhere. But once you hit complex queries with dynamic conditions, JPA’s Specification and QueryDSL start feeling clunky. spring-data-jpa-extra tries to give you the best of both worlds: keep JPA’s simplicity while writing dynamic SQL as flexibly as MyBatis.
Project Background
It’s a Java project with 401 stars, not exactly viral but genuinely useful. The author’s idea is straightforward: JPA’s @Query annotation only handles static JPQL/SQL, no dynamic conditions. MyBatis XML templates are flexible but require maintaining separate XML files. Why not combine them? So this extension brings template engines (Freemarker, Velocity) into JPA for dynamic SQL.
The project supports Spring Boot 2+ and Spring 5+, and the master branch is still maintained.
Core Features
Template-Based Dynamic Queries. The core capability. You put .ftl (Freemarker) or .vm (Velocity) template files in your resources directory, then reference them in your Repository interface. Templates support if, foreach logic — dynamically building SQL based on input parameters. Think user search with optional username, date range, and status filters. Way cleaner than Specifications.
Compatible with Native JPA. It’s an extension, not a replacement. You still get all JpaRepository methods, @Entity and @Table work exactly the same. Just add a @TemplateQuery annotation pointing to your template file. Very low impact on existing JPA projects.
Multiple Template Engines. Supports both Freemarker and Velocity out of the box. Freemarker is more powerful, Velocity is lighter. I tried the Freemarker version — syntax is very similar to MyBatis XML dynamic tags, easy to pick up.
Seamless Paging and Sorting. Return types can be Page, Slice, or List — exactly like normal JPA queries. Spring Data’s Pageable parameter just works, no extra handling needed.
Quick Start
Maven dependency:
<dependency>
<groupId>com.slyak</groupId>
<artifactId>spring-data-jpa-extra</artifactId>
<version>3.0.0</version>
</dependency>
Repository interface:
public interface UserRepository extends GenericJpaRepository<User, Long> {
@TemplateQuery
List<User> findByQuery(UserQuery query);
}
Template file at 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>
Then just call userRepository.findByQuery(query). The flow is almost identical to MyBatis, but JPA underneath.
Pros and Cons
Pros:
- Dynamic SQL is intuitive, way simpler than Specifications or Criteria API
- Doesn’t break existing JPA project structure, low incremental adoption cost
- Template files are separate, SQL lives in one place, easy to maintain
- Supports mainstream template engines, flexible choice
- Native paging and sorting support, no custom wrapping needed
Cons:
- 401 stars means small community, might not find answers to edge cases
- Template files in resources get messy as projects grow
- No official Spring Boot Starter, you configure Beans manually
- Error messages aren’t friendly — template mistakes produce vague runtime errors
- Compared to QueryDSL, type safety is gone — wrong field names surface at runtime
Comparison
| Approach | Dynamic SQL | Type Safety | Learning Curve | Intrusiveness | Community |
|---|---|---|---|---|---|
| spring-data-jpa-extra | ✅ Templates | ❌ | Low | Low | Low |
| QueryDSL | ✅ DSL | ✅ | Medium | Medium | High |
| JPA Specification | ✅ API | ✅ | High | Low | High |
| MyBatis | ✅ XML/Annotations | ❌ | Low | High | Huge |
| jOOQ | ✅ DSL | ✅ | Medium | Medium | Medium |
Compared to MyBatis, the advantage is not maintaining a separate ORM stack — JPA’s caching, association mapping all still work. Compared to QueryDSL, the advantage is more intuitive dynamic SQL without learning a DSL syntax. But if your project is already deep into QueryDSL, migrating probably isn’t worth it.
Who It’s For
Three scenarios fit well:
- Existing JPA projects that occasionally need complex queries — not worth introducing MyBatis for a few queries, this extension fills the gap
- Teams familiar with MyBatis syntax, trying JPA — template syntax lowers the migration barrier
- Small-to-medium projects that don’t want QueryDSL — QueryDSL setup is complex, this is much lighter
My practical takeaway: this library genuinely solves a real JPA pain point. But its limitations are clear too — low star count means limited community support, so you’ll need to test it thoroughly before production use. For critical queries in core systems, I’d probably still go with QueryDSL or straight MyBatis. But for internal tools, admin dashboards, and similar scenarios, it’s perfectly adequate and saves a lot of effort.
About the Author
Liudingyu is a full-stack developer and heavy GitHub user. With 900+ starred repos over the past 3 years, this site only covers tools I’ve actually used or deeply researched.
📧 Found a great tool to recommend? Email [email protected]
广告