web-dev-qa-db-ja.com

Spring JpaRepository:同じトランザクションでdelete()とそれに続くsave()

私のエンティティには、自動生成された主キー(id)とビジネスキー(名前空間)の両方があります。古いレコードを置き換えてレコードを更新する必要があります。それで、私はそれをビジネスキーで検索し、それを削除して、新しいエンティティを保存します。これは、各操作が独自のトランザクションである場合に機能します。しかし、それらすべてを同じトランザクションに入れると、save()が実行されるまでに、delete()がまだ実行されていないため、制約違反が発生します。

transactionTemplate.execute(status -> {
    MyEntity oldEntity = repository.findByNamespace(namespace);
    if (oldEntity != null) {
        repository.delete(oldEntity);
    }
    repository.save(newEntity);
    return null;
});

私は実際に追加することでそれをバイパスすることができました

repository.flush();

しかし、なぜこのflush()が必要なのかよくわかりません。

12
Pavel Petrov

Repository.flush()は、EntityManager.flush()を呼び出して、データベースへの変更をフラッシュするためです。したがって、delete()の後に変更をフラッシュすると、SQLが実行され、次の保存に問題はありません。

フラッシュを呼び出さない場合、トランザクションのコミット時間を期限として変更をフラッシュするタイミングを決定するのは永続性プロバイダー次第です。また、プロバイダーは特定の順序で変更をフラッシュしないため、操作が成功する場合と失敗する場合があります。通常、プロバイダーはコミット時間がフラッシュされるまで待機しますが、フラッシュモードを設定することでそれに影響を与えることができます。

for entitymanager
EntityManager.setFlushMode(FlushModeType type);

or for query
Query.setFlushMode(FlushModeType type);

Spring data JPAにも同等の設定があると思いますが、どれなのか正確にはわかりません。

ただし、変更をすぐにフラッシュするとパフォーマンスが低下するため、使用するときは注意が必要です。特定のケースでは、エンティティを更新してから削除してから、同じビジネスキーで新しいエンティティを永続化することをお勧めします。

9
miljanm