On this page
Spring Data JPA
Spring Data JPA simplifies data access by providing a repository abstraction that eliminates boilerplate DAO code. It builds on JPA and Hibernate.
Setup
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
spring:
datasource:
url: jdbc:h2:mem:testdb
jpa:
hibernate:
ddl-auto: update
show-sql: true
properties:
hibernate:
format_sql: true
Entity
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String email;
private String name;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private List<Order> orders = new ArrayList<>();
}
Repository Interface
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByEmail(String email);
List<User> findByNameContainingIgnoreCase(String name);
boolean existsByEmail(String email);
@Query("SELECT u FROM User u WHERE u.createdAt > :since")
List<User> findRecentUsers(@Param("since") LocalDateTime since);
@Modifying
@Query("UPDATE User u SET u.active = false WHERE u.lastLogin < :cutoff")
int deactivateInactiveUsers(@Param("cutoff") LocalDateTime cutoff);
}
Spring Data generates implementations at runtime — no boilerplate needed.
Derived Query Methods
| Method prefix | Example | Generated SQL |
|---|---|---|
findBy |
findByEmail(String email) |
WHERE email = ? |
findBy...And |
findByNameAndActive |
WHERE name = ? AND active = ? |
findBy...Or |
findByNameOrEmail |
WHERE name = ? OR email = ? |
findBy...OrderBy |
findByActiveOrderByNameDesc |
ORDER BY name DESC |
countBy |
countByActiveTrue |
SELECT COUNT(*) WHERE active = true |
deleteBy |
deleteByEmail |
DELETE WHERE email = ? |
Pagination and Sorting
Page<User> findByActiveTrue(Pageable pageable);
// Usage
Page<User> page = userRepository.findByActiveTrue(
PageRequest.of(0, 20, Sort.by("name").ascending()));
Specifications (Dynamic Queries)
public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> { }
Specification<User> spec = (root, query, cb) -> {
List<Predicate> predicates = new ArrayList<>();
if (name != null) predicates.add(cb.like(root.get("name"), "%" + name + "%"));
if (active != null) predicates.add(cb.equal(root.get("active"), active));
return cb.and(predicates.toArray(new Predicate[0]));
};
Page<User> results = userRepository.findAll(spec, pageable);
Auditing
@Entity
@EntityListeners(AuditingEntityListener.class)
public class User {
@CreatedDate
private LocalDateTime createdAt;
@LastModifiedDate
private LocalDateTime updatedAt;
@CreatedBy
private String createdBy;
}
@EnableJpaAuditing
@SpringBootApplication
public class Application { }
Best Practices
- Extend
JpaRepositoryfor full CRUD + pagination support - Use derived queries for simple lookups;
@Queryfor complex ones - Use
@Modifyingwith@Transactionalfor update/delete queries - Prefer Specifications or QueryDSL for dynamic query building
- Enable auditing for automatic timestamp tracking