Spring Data JPA is a powerful tool for building Spring-powered applications that use JPA (Java Persistence API) for data access layers. It provides an extra layer of abstraction on top of existing JPA providers enabling applications to communicate with different data access technologies through a simple and consistent API.

The actual strength of Spring Data JPA lies in the repository abstraction. It abstracts the data store-specific implementation details and allows us to write the business logic code on a higher abstraction level.

We only need to learn how to use the Spring Data repository interfaces instead of worrying about these interfaces' implementation. Spring Data provides the implementation for these repository interfaces out of the box.

In this article, you'll learn in detail about different types of Spring Data repository interfaces and their features. There are three popular repository interfaces that you should know while using Spring Data JPA:

  1. CrudRepository — Interface for generic CRUD (Create, Read, Update, and Delete) operations on a repository for a specific type.
  2. PagingAndSortingRepository — Extension of CrudRepository to provide additional methods to retrieve entities using the pagination and sorting abstraction.
  3. JpaRepository — Extension of PagingAndSortingRepository to provide JPA-related methods such as flushing the persistence context and deleting records in a batch. Because of inheritance, it contains all functions of the first two repository interfaces.

All these repository interfaces directly or indirectly extend the top-level Spring Data Repository interface. It acts as a central repository maker interface and captures the domain type to manage and the domain type's ID type.

Let us look at the CrudRepository, PagingAndSortingRepository, and JpaRepository repositories and their methods.

CrudRepository Interface

As the name suggests, the CrudRepository interface defines a repository that provides standard CRUD methods for creating, reading, updating, and deleting entities.

Here is what the CrudRepository interface definition looks like:

@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {

    <S extends T> S save(S entity);

    <S extends T> Iterable<S> saveAll(Iterable<S> entities);

    Optional<T> findById(ID id);

    boolean existsById(ID id);

    Iterable<T> findAll();

    Iterable<T> findAllById(Iterable<ID> ids);

    long count();

    void deleteById(ID id);

    void delete(T entity);

    void deleteAll(Iterable<? extends T> entities);

    void deleteAll();
}

Let us now look at all the above methods one by one:

  • save() — Saves a given entity. The persisted entity will be returned with all auto-generated and default fields being initialized.
  • saveAll() — Saves an iterable of entities. It returns all persisted entities as iterable.
  • findById() — Retrieves a single entity based on the primary key value.
  • existsById() — Returns whether an entity with the given ID exists.
  • findAll() — Returns an iterable of all existing entities of the type in the database.
  • findAllById() — Returns a iterable of all entities that match the given IDs.
  • count() — Returns the total number of entities available.
  • deleteById() — Deletes an entity with the given ID.
  • delete() — Finds and deletes the matching entity to the given entity.
  • deleteAll() — Deletes all entities that match in the given iterable. If no iterable is provided, it deletes all entities.

As you can see above, the CrudRepository interface provides typical CRUD functionality for managing entities.

To use this repository interface in your application, just create a new Java interface that extends the CrudRepository, as shown below:

public interface MovieRepository extends CrudRepository<Movie, Long> { }

Check out the Accessing Data with Spring Data JPA and MySQL tutorial to learn more about using CrudRepository for manipulating data.

PagingAndSortingRepository Interface

The PagingAndSortingRepository interface is an extension of CrudRepository that provides two additional methods for applying dynamic pagination and sorting to query results.

Here is what the PagingAndSortingRepository definition looks like:

@NoRepositoryBean
public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {

    Iterable<T> findAll(Sort sort);

    Page<T> findAll(Pageable pageable);
}
  • findAll(Sort sort) — Returns all entities sorted by the given Sort object.
  • findAll(Pageable pageable) — Returns a Page of entities that match the paging conditions provided by the given Pageable object.

Let us create a new repository interface that extends the PagingAndSortingRepository interface:

public interface SongRepository extends PagingAndSortingRepository<Song, Long> { }

To apply dynamic sorting to the query results, you need to create an instance of Sort and pass it as a parameter to findAll():

Sort sort = Sort.by("title").descending();
List<Song> songs = songRepository.findAll(sort);

If you want to paginate the query results, you need to create an instance of the Pageable interface as follows:

Pageable pageable = PageRequest.of(0, 10);
Page<Song> songs = songRepository.findAll(pageable);

You can even combine the sorting with the pagination by using the Pageable interface:

Pageable pageable = PageRequest.of(0, 10, Sort.by("title").descending());
Page<Song> songs = songRepository.findAll(pageable);

JpaRepository Interface

Finally, let us look at the JpaRepository interface definition:

@NoRepositoryBean
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {

    List<T> findAll();

    List<T> findAll(Sort sort);

    List<T> findAllById(Iterable<ID> ids);

    <S extends T> List<S> saveAll(Iterable<S> entities);

    void flush();

    <S extends T> S saveAndFlush(S entity);

    void deleteInBatch(Iterable<T> entities);

    void deleteAllInBatch();

    T getOne(ID id);
    
    @Override
    <S extends T> List<S> findAll(Example<S> example);

    @Override
    <S extends T> List<S> findAll(Example<S> example, Sort sort);
}

Most of the above JpaRepository methods are inherited from the PagingAndSortingRepository and QueryByExampleExecutor interfaces. Let us look at the additional methods:

  • flush() — Flushes all pending changes to the database.
  • saveAndFlush() — Saves the given entity and flushes changes instantly to the database.
  • deleteInBatch() — Deletes the given entities in a batch by using a single query.
  • deleteAllInBatch() — Deletes all entities in a batch call.
  • getOne() — Returns a single entity based on the given primary key value.

Since the JpaRepository repository extends the PagingAndSortingRepository, it inherits all methods from both the PagingAndSortingRepository and CrudRepository interfaces.

Using Spring Data Repositories

To use a Spring Data repository, you only need to create a new repository interface and extend any of the above-mentioned repositories.

The following example defines a CatRepository interface by extending the Spring Data JPA's JpaRepository and also declares query methods to retrieve Cat entities from the database:

public interface CatRepository extends JpaRepository<Cat, Long> {

    Cat findByName(String name);
    
    List<Cat> findByColor(String color);

    Page<Cat> findByAgeLessThan(int age, Pageable pageable)
}

Further Reading

To learn more about Spring Data JPA, check out the following articles:

✌️ Like this article? Follow me on Twitter and LinkedIn. You can also subscribe to RSS Feed.