1. 序章

この短いチュートリアルでは、Spring DataJPA@Queryアノテーションを使用して更新クエリを作成する方法を学習します。 これは、@Modifyingアノテーションを使用して実現します。

まず、メモリを更新するために、 Spring DataJPAを使用してクエリを実行する方法を読むことができます。 その後、@Queryおよび@Modifyingアノテーションの使用について詳しく説明します。 最後に、変更クエリを使用するときに永続コンテキストの状態を管理する方法について説明します。

2. SpringDataJPAでのクエリ

まず、JPAがデータベース内のデータをクエリするために提供する3つのメカニズムを要約してみましょう。

  • クエリメソッド
  • @Queryアノテーション
  • カスタムリポジトリの実装

これらのメカニズムを説明するために、Userクラスと対応するSpring DataJPAリポジトリーを作成しましょう。

@Entity
@Table(name = "users", schema = "users")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    private String name;
    private LocalDate creationDate;
    private LocalDate lastLoginDate;
    private boolean active;
    private String email;

}
public interface UserRepository extends JpaRepository<User, Integer> {}

クエリメソッドメカニズムを使用すると、メソッド名からクエリを取得してデータを操作できます。

List<User> findAllByName(String name);
void deleteAllByCreationDateAfter(LocalDate date);

この例では、名前でユーザーを取得するクエリ、または特定の日付より後の作成日を持つユーザーを削除するクエリを見つけることができます。

@Query アノテーションに関しては、は、@Queryアノテーションに特定のJPQLまたはSQLクエリを記述する機会を提供します。

@Query("select u from User u where u.email like '%@gmail.com'")
List<User> findUsersWithGmailAddress();

このコードスニペットでは、 @gmail.comのメールアドレスを持つユーザーを取得するクエリを確認できます。

最初のメカニズムでは、データを取得または削除できます。 2番目のメカニズムについては、ほとんどすべてのクエリを実行できます。 ただし、クエリを更新するには、@Modifyingアノテーションを追加する必要があります。 これがこのチュートリアルのトピックになります。

3. @Modifyingアノテーションの使用

@Modifyingアノテーションは、 @Query アノテーションを拡張して、 SELECT クエリだけでなく、INSERTも実行できるようにするために使用されます。 UPDATE DELETE 、さらにはDDLクエリ。

それでは、この注釈を少し試してみましょう。

まず、 @ModifyingUPDATEクエリの例を見てみましょう。

@Modifying
@Query("update User u set u.active = false where u.lastLoginDate < :date")
void deactivateUsersNotLoggedInSince(@Param("date") LocalDate date);

ここでは、特定の日付以降にログインしていないユーザーを非アクティブ化しています。

非アクティブ化されたユーザーを削除する別のユーザーを試してみましょう。

@Modifying
@Query("delete User u where u.active = false")
int deleteDeactivatedUsers();

ご覧のとおり、このメソッドは整数を返します。 これはSpring DataJPA@Modifyingクエリの機能であり、更新されたエンティティの数を提供します。

@Query を使用して削除クエリを実行すると、Spring DataJPAのdeleteBy名前から派生したクエリメソッドとは動作が異なることに注意してください。 後者は、最初にデータベースからエンティティをフェッチし、次にそれらを1つずつ削除します。 これは、ライフサイクルメソッド@PreRemoveがこれらのエンティティで呼び出されることを意味します。 ただし、前者の場合、データベースに対して1つのクエリが実行されます。

最後に、DDLクエリを使用してdeleted列をUSERSテーブルに追加しましょう。

@Modifying
@Query(value = "alter table USERS.USERS add column deleted int(1) not null default 0", nativeQuery = true)
void addDeletedColumn();

残念ながら、変更クエリを使用すると、基礎となる永続コンテキストが古くなります。 ただし、この状況を管理することは可能です。 それが次のセクションの主題です。

3.1. @Modifyingアノテーションを使用しなかった結果

削除クエリに@Modifyingアノテーションを付けないとどうなるか見てみましょう。

このため、さらに別のメソッドを作成する必要があります。

@Query("delete User u where u.active = false")
int deleteDeactivatedUsersWithNoModifyingAnnotation();

注釈が欠落していることに注意してください。

上記のメソッドを実行すると、InvalidDataAccessApiUsage例外が発生します。

org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.hql.internal.QueryExecutionRequestException: 
Not supported for DML operations [delete com.baeldung.boot.domain.User u where u.active = false]
(...)

エラーメッセージは非常に明確です。 クエリはDML操作ではサポートされていません

4. 永続性コンテキストの管理

変更クエリが永続コンテキストに含まれるエンティティを変更すると、このコンテキストは古くなります。この状況を管理する1つの方法は、永続コンテキストをクリアするです。 そうすることで、永続コンテキストが次回データベースからエンティティをフェッチすることを確認します。

ただし、 EntityManagerclear()メソッドを明示的に呼び出す必要はありません。 @ModifyingアノテーションからclearAutomaticallyプロパティを使用できます。

@Modifying(clearAutomatically = true)

このようにして、クエリの実行後に永続コンテキストがクリアされるようにします。

ただし、永続コンテキストにフラッシュされていない変更が含まれている場合、それをクリアすると、保存されていない変更が削除されます。 幸い、この場合に使用できるアノテーションの別のプロパティ、flushAutomaticallyがあります。

@Modifying(flushAutomatically = true)

これで、クエリが実行される前にEntityManagerがフラッシュされます。

5. 結論

これで、@Modifyingアノテーションに関するこの簡単な記事は終わりです。 このアノテーションを使用して、 INSERT、UPDATE、DELETE、、さらにはDDLなどの更新クエリを実行する方法を学びました。 その後、clearAutomaticallyおよびflushAutomaticallyプロパティを使用して永続コンテキストの状態を管理する方法について説明しました。

いつものように、この記事の完全なコードはGitHubから入手できます。