100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Java

Repositories in Spring Data

Understand the Repository interface hierarchy in Spring Data — from Repository and CrudRepository to PagingAndSortingRepository and JpaRepository.

Data LayerBeginner9 min readJul 10, 2026
Analogies

The Repository Interface Hierarchy

Spring Data organizes repository capabilities into a layered hierarchy of interfaces, each adding more functionality: the marker interface Repository<T, ID> has no methods and simply flags a type for component scanning; CrudRepository<T, ID> adds basic create-read-update-delete methods like save, findById, findAll, and deleteById; PagingAndSortingRepository<T, ID> adds findAll(Pageable) and findAll(Sort) for paged and ordered results; and JpaRepository<T, ID>, the interface most Spring Boot developers extend directly, combines all of the above with JPA-specific extras like flush(), saveAndFlush(), and batch deletion via deleteAllInBatch().

🏏

Cricket analogy: This hierarchy is like the tiers of domestic cricket — club level (Repository, the base marker), state level (CrudRepository, basic operations), and international level (JpaRepository), each tier layering on more capability and structure than the one below.

Query Method Derivation

One of Spring Data JPA's signature features is deriving SQL from method names: declaring List<Book> findByAuthorLastNameAndStatus(String lastName, BookStatus status) on a repository interface causes Spring Data to parse the method name at startup, recognize the By keyword, split on And/Or, and generate the equivalent JPQL automatically — no method body required. Supported keywords extend beyond simple equality to include Containing, StartingWith, GreaterThan, Between, OrderBy, and IgnoreCase, letting a surprisingly large slice of everyday queries be expressed purely through interface method signatures.

🏏

Cricket analogy: Query derivation is like a scorer's shorthand notation where 'c Dhoni b Bumrah' unambiguously encodes 'caught by Dhoni, bowled by Bumrah' — a compact naming convention that expands into the full, precise meaning automatically.

Custom Query Methods with @Query

When a query is too complex to express through derived method names — or when the derived name would become unreadably long — you annotate a repository method with @Query and supply JPQL (or, with nativeQuery = true, raw SQL) directly. Named parameters are bound with :paramName in the query string and matched to method arguments annotated @Param("paramName"), which keeps the binding explicit and refactor-safe compared to relying purely on positional parameters.

🏏

Cricket analogy: @Query is like a captain calling a specific, unconventional field placement by hand rather than relying on the standard pre-set fields — sometimes the situation demands an exact, custom instruction instead of the default convention.

java
public interface BookRepository extends JpaRepository<Book, Long> {

    // Derived query — no implementation needed
    List<Book> findByAuthorLastNameAndStatus(String lastName, BookStatus status);

    List<Book> findByTitleContainingIgnoreCaseOrderByTitleAsc(String keyword);

    // Custom JPQL query with named parameters
    @Query("SELECT b FROM Book b WHERE b.author.id = :authorId AND b.publishedYear >= :sinceYear")
    List<Book> findRecentBooksByAuthor(@Param("authorId") Long authorId,
                                        @Param("sinceYear") int sinceYear);

    // Native SQL query, useful for database-specific features
    @Query(value = "SELECT * FROM books WHERE to_tsvector('english', title) @@ plainto_tsquery(:term)",
           nativeQuery = true)
    List<Book> fullTextSearch(@Param("term") String term);

    // Paging support inherited from PagingAndSortingRepository via JpaRepository
    Page<Book> findByStatus(BookStatus status, Pageable pageable);
}

Custom Repository Implementations

For logic that neither derived methods nor @Query can express cleanly — dynamic queries built with the JPA Criteria API, integration with a search engine, or complex multi-step logic — Spring Data supports fragment interfaces: you declare an interface like BookRepositoryCustom with the method signature, provide an implementation class named BookRepositoryCustomImpl (the Impl suffix is the default convention Spring Data looks for), and have your main BookRepository extend both JpaRepository and BookRepositoryCustom. Spring Data then composes all three into a single proxy at runtime, so callers just see one cohesive BookRepository interface.

🏏

Cricket analogy: Composing a custom fragment into a repository is like a franchise signing a specialist death-bowling coach who only handles the last four overs, while the rest of the coaching staff runs everything else — together they form one seamless team.

Spring Data repository proxies are created lazily by the Spring Data JPA infrastructure through @EnableJpaRepositories (auto-enabled by Spring Boot's auto-configuration), which scans for interfaces extending Repository and generates a SimpleJpaRepository-backed proxy for each — you never implement JpaRepository's inherited methods yourself.

Derived query method names can become unwieldy and error-prone once you chain more than two or three conditions — a name like findByStatusAndAuthorLastNameAndPublishedYearGreaterThanAndTitleContainingIgnoreCase is hard to read and easy to typo. Switch to @Query with JPQL once a derived method name stops being self-explanatory at a glance.

  • Repository, CrudRepository, PagingAndSortingRepository, and JpaRepository form a layered hierarchy of increasing capability.
  • Method-name query derivation parses keywords like And, Or, Containing, and OrderBy to generate JPQL automatically.
  • @Query lets you supply explicit JPQL or, with nativeQuery = true, raw SQL for cases derivation can't express.
  • @Param binds named parameters (:paramName) to method arguments, which is safer and more refactor-friendly than positional binding.
  • Custom fragment interfaces (suffixed Impl) let you inject Criteria API or other bespoke logic into a composed repository proxy.
  • Spring Boot auto-enables repository scanning, generating SimpleJpaRepository-backed proxies without manual configuration.
  • Switch from derived method names to explicit @Query once the method name becomes long or hard to read at a glance.

Practice what you learned

Was this page helpful?

Topics covered

#Java#SpringBootStudyNotes#WebDevelopment#RepositoriesInSpringData#Repositories#Spring#Data#Repository#StudyNotes#SkillVeris