Unlock 6 Powerful Spring Data JPA Features for Faster Development

This article introduces Spring Data JPA and demonstrates six advanced capabilities—including Optional return types, Stream API, asynchronous CompletableFuture queries, offset‑based scrolling, and keyset‑based scrolling—each illustrated with concise code examples and execution results to boost productivity and performance.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Unlock 6 Powerful Spring Data JPA Features for Faster Development

Introduction

Spring Data JPA is a module of the Spring framework that simplifies Java Persistence API (JPA) operations, reducing boilerplate code and improving database access efficiency. It provides a unified data access interface such as JpaRepository and automatic method name resolution, allowing developers to avoid writing SQL manually. Core benefits include lower development cost, rapid CRUD construction, support for custom query methods, pagination, sorting, and enhanced maintainability.

Key Features Demonstrated

2.2 Optional Return Values

Methods can return java.util.Optional (or Guava's Optional) to express that a query may produce zero or one result. If no result is found, Optional.empty() is returned; multiple results trigger IncorrectResultSizeDataAccessException.

public interface BookRepository extends JpaRepository<Book, Long> {
    Optional<Book> findByTitle(String title);
}

Using Optional forces explicit null‑handling, improving code safety and readability.

2.3 Stream API

Instead of loading all results into a collection, Spring Data JPA can return a Java 8 Stream, reducing memory consumption for large datasets.

Stream<Book> findByPriceGreaterThan(BigDecimal price);
@Resource
private BookRepository bookRepository;

@Test
public void testStream() {
    this.bookRepository.findByPriceGreaterThan(BigDecimal.ZERO)
        .forEach(System.out::println);
}

The stream operation must be executed within a transaction.

@Test
@Transactional
public void testStream() {
    // ...
}

2.4 CompletableFuture + @Async

Methods can return CompletableFuture and be annotated with @Async to run asynchronously, allowing the caller to receive a Future immediately while the query executes in another thread.

@Async
CompletableFuture<Book> findByIsbn(String isbn);

This improves response speed and system concurrency for high‑latency operations.

2.5 Scroll Query (Offset‑Based)

Offset‑based scrolling retrieves results in fixed‑size windows, useful for iterating large result sets.

Window<Book> findFirst5ByRatingOrderById(String rating, OffsetScrollPosition position);
@Test
public void testScrollWindow() {
    String rating = "1";
    OffsetScrollPosition offset = ScrollPosition.offset();
    Window<Book> books = bookRepository.findFirst5ByRatingOrderById(rating, offset);
    do {
        books.forEach(System.out::println);
        System.err.println("------------------------------------");
        books = bookRepository.findFirst5ByRatingOrderById(rating,
            (OffsetScrollPosition) books.positionAt(books.size() - 1));
    } while (!books.isEmpty() && books.hasNext());
}

2.6 Scroll Query (Keyset‑Based)

Keyset filtering avoids full result‑set materialization by using the last record’s key (e.g., id) for subsequent queries, offering better performance for large data sets.

Window<Book> findFirst5ByRatingOrderById(String rating, KeysetScrollPosition position);
@Test
public void testScrollWindow() {
    String rating = "1";
    WindowIterator<Book> books = WindowIterator.of(
        position -> bookRepository.findFirst5ByRatingOrderById(rating, (KeysetScrollPosition) position)
    ).startingAt(ScrollPosition.keyset());
    books.forEachRemaining(System.out::println);
}

Entity Definition

@Entity
public class Book {
    @Id
    private Long id;
    private String title;
    private String isbn;
    private String description;
    private Integer page;
    private BigDecimal price;
    private String rating;
}

Sample Data

(An illustrative image of sample data is shown below.)

Sample data
Sample data

Execution Results

Console output for the Stream example:

Stream output
Stream output

Console output after adding @Transactional:

Transactional output
Transactional output

Console output for offset‑based scrolling:

Offset scroll output
Offset scroll output

Console output for keyset‑based scrolling:

Keyset scroll output
Keyset scroll output
PaginationAsyncOptionalStream APISpring Data JPAKeyset Scrolling
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.