Definitions

Spring Data JPA: Repository abstraction layer simplifying data access. Provides CRUD operations, query methods, pagination without manual implementation.

Repository: Interface extending JpaRepository/CrudRepository. Spring auto-implements CRUD methods and custom query methods.

JpaRepository: Interface extending CrudRepository adding batch operations, flush, deleteInBatch methods. Most commonly used repository type.

Query Method: Method in repository interface whose name/annotations define query logic. Spring generates SQL based on method signature.

@Query: Annotation specifying custom JPQL or native SQL query. Overrides default query generation from method name.

Specification: Dynamic query builder for complex queries. Type-safe alternative to query string concatenation.

Page / Slice: Result wrappers for paginated data. Page includes total count; Slice doesn’t (faster for large datasets).


Q&A

Why use Spring Data JPA instead of plain Hibernate?

Spring Data JPA provides repository abstraction; no custom implementation needed. Query method naming convention generates queries automatically. Pagination, sorting built-in. Less boilerplate; focus on business logic. Consistent interface across multiple data sources (JDBC, MongoDB via Spring Data).

How do you define query methods in Spring Data JPA?

Name methods following convention: findBy, getBy, readBy, queryBy, searchBy, streamBy followed by property name. Example: findByEmail() generates query filtering by email. Combine conditions: findByEmailAndStatus(). Add @Query for custom JPQL/SQL.

What’s the difference between @Query with JPQL and native SQL?

JPQL operates on entities/properties; queries portable across databases. Native SQL uses database-specific syntax; faster but database-dependent. Use JPQL by default; native SQL when JPQL insufficient (stored procedures, complex database-specific queries).

How do you implement pagination in Spring Data JPA?

Define repository method accepting Pageable parameter: Page<User> findByStatus(String status, Pageable pageable). Call with PageRequest: userRepository.findByStatus("active", PageRequest.of(0, 10)). Returns Page with data, total count, page info.

What are specifications and when use them?

Specifications enable dynamic query building; implement Specification interface defining Predicates. Use for complex filtering with multiple optional criteria. More type-safe than query string concatenation; cleaner than complex method names.

Can you use named queries with Spring Data JPA?

Yes, define @NamedQuery on entity, then use in repository with @Query(name="..."). Or use @Query directly in repository. Named queries cacheable, improved performance for frequently used queries.


Code Examples

Example - Repository Interface:

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    
    Optional<User> findByEmail(String email);
    
    List<User> findByStatusOrderByCreatedAtDesc(String status);
    
    @Query("from User u where u.email = :email")
    Optional<User> findUserByEmail(@Param("email") String email);
    
    @Query(value = "SELECT * FROM users WHERE age > ?1", 
           nativeQuery = true)
    List<User> findUsersOlderThan(int age);
}

Example - Pagination:

@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;
    
    public Page<User> getActiveUsers(int page, int size) {
        Pageable pageable = PageRequest.of(page, size, 
            Sort.by("createdAt").descending());
        return userRepository.findByStatus("active", pageable);
    }
}

Example - Specification:

public class UserSpecification {
    public static Specification<User> hasEmail(String email) {
        return (root, query, cb) -> cb.equal(root.get("email"), email);
    }
    
    public static Specification<User> hasStatus(String status) {
        return (root, query, cb) -> cb.equal(root.get("status"), status);
    }
}
 
// Usage
List<User> users = userRepository.findAll(
    UserSpecification.hasEmail("test@example.com")
        .and(UserSpecification.hasStatus("active"))
);

Key Points

  • Query Method Naming: Master naming conventions for productivity; covers 80% of queries without custom @Query.
  • Pagination Performance: For large datasets, use Slice instead of Page (doesn’t count total).
  • Custom Repositories: Extend repositories for complex logic; implement custom interface, inject repository.
  • Batch Operations: Use batch methods for performance with large inserts/updates.