web-dev-qa-db-ja.com

JPA / Hibernateでのflush()の正しい使用

Flush()メソッドに関する情報を収集していましたが、それをいつ使用するか、どのように正しく使用するかは明確ではありません。私が読んだことから、私の理解では、永続コンテキストの内容はデータベースと同期されるということです。 e。未処理のステートメントの発行またはエンティティデータの更新。

これで、2つのエンティティAB(1対1の関係にありますが、JPAによって実施またはモデル化されていない)の次のシナリオが得られました。 Aには、手動で設定される複合PKがあり、自動生成されたIDENTITYフィールドrecordIdもあります。このrecordIdは、Bへの外部キーとしてエンティティAに書き込まれる必要があります。 1つのトランザクションでABを保存しています。問題は、Aem.flush()を呼び出した後にem.persist()を明示的に呼び出さない限り、自動生成された値A.recordIdがトランザクション内で使用できないことです。 (自動生成されたIDENTITY PKがある場合、値はエンティティで直接更新されますが、ここではそうではありません。)

em.flush()は、トランザクション内で使用するときに害を及ぼす可能性がありますか?

106
MicSim

おそらくem.flush()の正確な詳細は実装依存です。一般的に、HibernateなどのJPAプロバイダーは、多くの場合、実際にトランザクションをコミットするまで、データベースに送信するはずのSQL命令をキャッシュできます。たとえば、em.persist()を呼び出すと、HibernateはデータベースINSERTを作成する必要があることを記憶していますが、トランザクションをコミットするまで実際に命令を実行しません。 Afaik、これは主にパフォーマンス上の理由で行われます。

とにかく、SQL命令をすぐに実行したい場合があります。通常、自動生成キーやデータベーストリガーなどの副作用の結果が必要な場合。

em.flush()が行うことは、内部SQL命令キャッシュを空にし、データベースに対して直ちに実行することです。

結論:害は発生しません。SQL命令をデータベースに送信する最適なタイミングに関するJPAプロバイダーの決定をオーバーライドしているため、パフォーマンスヒット(マイナー)のみが発生します。

136
Flavio

実際、em.flush()は、キャッシュされたSQLコマンドを送信するだけではありません。永続コンテキストを基になるデータベースに同期しようとします。キャッシュに同期するコレクションが含まれている場合、プロセスで多くの時間を消費する可能性があります。

使用上の注意。

2

Em.flush()は、トランザクション内で使用するときに害を及ぼす可能性がありますか?

はい、必要以上に長い期間データベースにロックを保持します。

一般に、JPAを使用する場合、トランザクション管理をコンテナに委任します(別名CMT-ビジネスメソッドで@Transactionalアノテーションを使用)。これは、メソッドに入るときにトランザクションが自動的に開始され、最後にコミット/ロールバックされることを意味します。 EntityManagerでデータベースの同期を処理できるようにすると、SQLステートメントの実行はコミットの直前にのみトリガーされ、データベースのロックが短命になります。そうでない場合、手動でフラッシュされた書き込み操作は、手動フラッシュと自動コミットの間でロックを保持する可能性があり、これは残りのメソッド実行時間に応じて長くなる可能性があります。

いくつかの操作が自動的にフラッシュをトリガーすることに注意してください:同じセッションに対してネイティブクエリを実行し(SQLクエリで到達できるようにEM状態をフラッシュする必要があります)、ネイティブ生成IDを使用してエンティティを挿入します(データベースによって生成されるため、insertステートメントはトリガーされるため、EMは生成されたIDを取得し、関係を適切に管理できます)

1
Gab