Spring Data JDBC

Spring Data JDBC is a pretty new module in the Spring Data family. It aims to simplify the implementation of JDBC-based repositories. Spring Data repositories, including JDBC-based ones, are inspired by the repository described in Domain-Driven Design by Eric Evans. This means that we are recommended to have a repository per Aggregate Root. Spring Data JDBC features CRUD operations for simple aggregates, supporting @Query annotations and entity life cycle events.

Be attentive—Spring Data JDBC and Spring JDBC are different modules!

To use Spring Data JDBC we have to modify the Book entity and apply the org.springframework.data.annotation.Id annotation to the id field. The repository requires an entity to have a unique identifier, so the Book entity refactored for use in repository looks like the following:

class Book {
   @Id
   private int id;
   private String title;

   // other parts are unchanged
}

Now let's define the BookRepository interface, deriving it from CrudRepository<Book, Integer>:

@Repository
public interface BookSpringDataJdbcRepository
   extends CrudRepository<Book, Integer> {                         // (1)

   @Query("SELECT * FROM book WHERE LENGTH(title) = " +            // (2)
          "(SELECT MAX(LENGTH(title)) FROM book)")
   List<Book> findByLongestTitle();                                // (2.1)

   @Query("SELECT * FROM book WHERE LENGTH(title) = " +
          "(SELECT MIN(LENGTH(title)) FROM book)")
   Stream<Book> findByShortestTitle();                             // (3)

   @Async                                                          // (4)
   @Query("SELECT * FROM book b " +
      "WHERE b.title = :title")
   CompletableFuture<Book> findBookByTitleAsync(                   // (4.1)
      @Param("title") String title);

   @Async                                                          // (5)
   @Query("SELECT * FROM book b " +
      "WHERE b.id > :fromId AND b.id < :toId")
   CompletableFuture<Stream<Book>> findBooksByIdBetweenAsync(      // (5.1)
      @Param("fromId") Integer from,
      @Param("toId") Integer to);
}

The preceding code is doing the following things:

  1. By extending CrudRepository, our book repository received a dozen methods for basic CRUD operations, such as save(...), saveAll(...), findById(...), deleteAll().
  2. It registers a custom method to find books with the longest title by providing a custom SQL defined in a @Query annotation. However, in contrast to Spring JDBC, we do not see any ResultSet transformations. JdbcTemplate is not required, and the only thing we have to write is an interface. Spring Framework generates the implementation, taking care of many pitfalls. As a result of the findByLongestTitle method (2.1), the repository returns a List container, so the client is only unblocked when the whole query result arrives.
  1. Alternatively, the repository may return a Stream of books, so when a client calls the findByShortestTitle method (3.1), depending on the underlying implementation, an API may allow processing the first element while the database still executes the query. Of course, this is only the case when the underlying implementation and the database itself supports this mode of operation.
  2. With the findBookByTitleAsync method (4.1)the repository leverages the asynchronous support of the Spring Framework. The method returns CompletableFuture so the client's thread won't be blocked while waiting for results. Unfortunately, an underlying thread still has to be locked due to the blocking manner of JDBC.
  3. Also, it is possible to combine CompletableFuture and Stream as done in the findBooksByIdBetweenAsync method (5.1). That way, the client's thread should not be blocked until the first rows arrive, and then the result set may be traversed in chunks. Unfortunately, for the first part of the execution, an underlying thread has to be blocked and the client's thread is later blocked when retrieving the next chunks of data. Such behavior is the best we can achieve with JDBC and without reactive support.

To inform Spring about the need to generate BookRepository implementation with Spring Data JDBC, we have to add the next dependency to our Spring Boot application:

compile('org.springframework.data:spring-data-jdbc:1.0.0.RELEASE')

It is also necessary to add the @EnableJdbcRepositories annotation to the application configuration. Under the hood, Spring Data JDBC uses Spring JDBC and NamedParameterJdbcTemplate, which was discussed previously.

Spring Data JDBC is a pretty small module that gives a convenient way to build a simple persistence layer for a small microservice. However, it is intentionally designed to be simple and not target ORM aspects such as caching, lazy-loading of entities, and complex entity relationships. For these purposes, the Java ecosystem has a separate specification called the Java Persistence API (JPA). 

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.142.12.207