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 the implementation of these interfaces. Spring Data provides an implementation for these repository interfaces out-of-the-box.

In this article, you'll learn in detail about different kinds of Spring Data repository interfaces and their features. There are three important 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 provides JPA related methods such as flushing the persistence context and deleting records in a batch. Because of inheritance, it contains all methods 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 as well as the domain type's id type.

Let us have a look at CrudRepository, PagingAndSortingRepository, and JpaRepository repositories and the methods they define.

CrudRepository Interface

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

Here is how 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 above methods one by one:

  • save() — Saves a given entity. The persisted entity will be returned with all auto-generated and default fields being initialised.
  • saveAll() — Saves an iterable of entities. It returns all persisted entities as an 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 available 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 how 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 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 PagingAndSortingRepository, it inherits all methods from both PagingAndSortingRepository and CrudRepository interfaces.

Using Spring Data Repositories

To use any Spring Data repository, all you need to do is just 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 retrieving 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 @attacomsian on Twitter. You can also follow me on LinkedIn and DEV. Buy me a coffee (cost $3)

Need help to start a new Spring Boot or MEAN stack project? I am available for contract work. Hire me to accomplish your business goals with engineering and design. Let’s talk about your project: hi@attacomsian.com.