1. 概要

Spring Dataは、オプション Stream API、CompleteableFutureなどのコアJava8機能をサポートするようになりました。

この簡単な記事では、フレームワークでこれらを使用する方法の例をいくつか紹介します。

2. オプション

CRUDリポジトリメソッドから始めましょう–これで結果がオプションにラップされます。

public interface CrudRepository<T, ID> extends Repository<T, ID> {
    
    Optional<T> findById(ID id);
    
}

オプションインスタンスを返す場合、値が存在しない可能性があることを示す便利なヒントです。 オプションの詳細については、こちらをご覧ください。

ここで行う必要があるのは、リターンタイプをオプションとして指定することだけです。

public interface UserRepository extends JpaRepository<User, Integer> {
    
    Optional<User> findOneByName(String name);
    
}

3. ストリームAPI

Spring Dataは、Java8の最も重要な機能の1つであるStreamAPIのサポートも提供します。

以前は、複数の結果を返す必要がある場合は常に、コレクションを返す必要がありました。

public interface UserRepository extends JpaRepository<User, Integer> {
    // ...
    List<User> findAll();
    // ...
}

この実装の問題の1つは、メモリの消費でした。

取得したすべてのオブジェクトを熱心にロードして保持する必要がありました。

ページングを活用することで改善できます。

public interface UserRepository extends JpaRepository<User, Integer> {
    // ...
    Page<User> findAll(Pageable pageable);
    // ...
}

シナリオによってはそれで十分ですが、他のシナリオでは、データを取得するために必要なリクエストの数が多いため、ページ付けは実際には方法ではありません。

Java 8 Stream APIおよびJPAプロバイダーのおかげで–リポジトリメソッドがオブジェクトのストリームのみを返すことを定義できるようになりました。

public interface UserRepository extends JpaRepository<User, Integer> {
    // ...
    Stream<User> findAllByName(String name);
    // ...
}

Spring Dataはプロバイダー固有の実装を使用して結果をストリーミングします(Hibernateは ScrollableResultSet を使用し、EclipseLinkは ScrollableCursor を使用します)。 これにより、メモリ消費量とデータベースへのクエリ呼び出しが削減されます。 そのため、前述の2つのソリューションよりもはるかに高速です。

ストリームを使用してデータを処理するには、ストリームを終了するときにストリームを閉じる必要があります

これは、 Streamclose()メソッドを呼び出すか、try-with-resourcesを使用して実行できます。

try (Stream<User> foundUsersStream 
  = userRepository.findAllByName(USER_NAME_ADAM)) {
 
assertThat(foundUsersStream.count(), equalTo(3l));

トランザクション内でリポジトリメソッドを呼び出すことも忘れないでください。 それ以外の場合は、例外が発生します。

org.springframework.dao.InvalidDataAccessApiUsageException Stream を実際に使用できるように、接続を開いたままにする周囲のトランザクションなしでストリーミングクエリメソッドを実行しようとしています。 ストリームを消費するコードが@Transactionalまたは(読み取り専用)トランザクションを宣言するその他の方法を使用していることを確認してください。

4. CompleteableFuture

Springデータリポジトリは、Java8のCompletableFutureおよび非同期メソッド実行用のSpringメカニズムのサポートにより非同期で実行できます。

@Async
CompletableFuture<User> findOneByStatus(Integer status);

このメソッドを呼び出すクライアントはすぐにfutureを返しますが、メソッドは別のスレッドで実行を継続します。

CompleteableFuture 処理の詳細については、こちらをご覧ください。

5. 結論

このチュートリアルでは、Java8の機能がSpringDataとどのように連携するかを示しました。

例の完全な実装は、Githubから入手できます。