Master Essential Spring Data JPA Methods: From save() to Dynamic Queries
This article introduces the most practical Spring Data JPA methods, explains when and why to use each one, and provides real‑world code examples ranging from basic CRUD operations to custom @Query, @Modifying, QBE, and dynamic specifications for advanced backend development.
Environment: Spring Boot 3.4.2
1. Introduction
Spring Data JPA, a member of the Spring Data family, simplifies building Spring‑driven applications that use JPA (Java Persistence API). It reduces the boilerplate needed for data‑access layers and offers a rich set of repository methods.
While basic methods like save(), findById(), and delete() cover most daily needs, larger projects benefit from the many additional capabilities JPA provides.
2. Practical Examples
2.1 save() and saveAll()
save(entity) – saves or updates a single entity.
saveAll(entities) – saves a collection of entities in one call.
List<User> users = List.of(
new User("Pack", "[email protected]"),
new User("Xg", "[email protected]")
);
userRepository.saveAll(users);Using saveAll() avoids looping over each entity and can be combined with batch‑insert settings for thousands of rows.
2.2 findById() and findAllById()
These methods are the preferred way to retrieve entities by primary key.
Optional<User> user = userRepository.findById(1L);
List<User> users = userRepository.findAllById(List.of(1L, 2L, 3L)); findById()returns an Optional, helping avoid NullPointerException but requiring a presence check.
2.3 getReferenceById()
Returns a lazy proxy without executing a query immediately. The query runs only when a property of the proxy is accessed, making it ideal for setting foreign‑key references.
User user = userRepository.getReferenceById(1L);2.4 existsById()
Checks whether a record exists without loading the entity, which is faster than findById() when only existence matters.
boolean exists = userRepository.existsById(1L);2.5 deleteById() and deleteAllById()
These methods load the entity before deletion, which can be inefficient for large datasets. Use a custom @Query with DELETE to bypass the select.
@Modifying
@Query("DELETE FROM User u WHERE u.email = :email")
void deleteByEmail(@Param("email") String email);2.6 count()
Returns the total number of rows. Useful for dashboards but can be slow on very large tables.
long count = userRepository.count();2.7 flush() and saveAndFlush()
Force immediate synchronization with the database, useful before subsequent operations in the same transaction or for debugging.
userRepository.saveAndFlush(user);Use when you need the entity persisted before other actions.
Helpful for troubleshooting transaction issues.
2.8 findAll(Sort) and findAll(Pageable)
For large tables, avoid findAll() without pagination. Use sorting and paging to limit memory usage.
List<User> users = userRepository.findAll(Sort.by("name"));
Page<User> page = userRepository.findAll(PageRequest.of(0, 20));2.9 @Query for custom queries
When derived query methods are insufficient, define JPQL or native SQL with @Query.
@Query("SELECT u FROM User u WHERE u.email LIKE %:keyword%")
List<User> searchByEmail(@Param("keyword") String keyword);
@Query(value = "SELECT * FROM users WHERE email LIKE %:keyword%", nativeQuery = true)
List<User> searchByEmailNative(@Param("keyword") String keyword);2.10 @Modifying for update/delete operations
Mark a query as modifying to execute UPDATE or DELETE without loading entities.
@Modifying
@Query("UPDATE User u SET u.name = :name WHERE u.id = :id")
void updateUserName(@Param("id") Long id, @Param("name") String name);2.11 Query‑by‑Example (QBE)
Build queries by providing an example entity; non‑null fields become criteria.
Emp emp = new Emp();
emp.setAge(age);
emp.setName("张三");
Example<Emp> example = Example.of(emp);
return empRepository.findOne(example);2.12 Dynamic specifications
Implement JpaSpecificationExecutor to construct predicates programmatically.
Specification<Product> spec = where(null);
if (name != null && !name.isEmpty()) {
spec = spec.and(ProductSpecifications.hasNameLike(name));
}
if (category != null && !category.isEmpty()) {
spec = spec.and(ProductSpecifications.hasCategory(category));
}
if (minPrice != null && maxPrice != null) {
spec = spec.and(ProductSpecifications.isPriceBetween(minPrice, maxPrice));
}
return productRepository.findAll(spec);Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
