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


110

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

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

em.flush()トランザクション内で使用すると害が生じる可能性がありますか?

回答:


148

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

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

em.flush()んと、内部SQL命令キャッシュを空にし、データベースにすぐにそれを実行することです。

結論:SQL命令をデータベースに送信する最適なタイミングに関するJPAプロバイダーの決定をオーバーライドしているため、害はありません。パフォーマンスに影響を与える可能性があるのはあなただけです。


1
彼が言った事。em.flush()の動作はjava.io.Flushable.flush()をエコーし​​、バッファリングされたすべてのデータが適切な宛先に送信されます。
エリック

4
flush()がデータベースにデータを送信する場合?その後に例外がスローされるとどうなりますか?エンティティマネージャーはすべてをロールバックしますか?最初のフラッシュで書き込まれたデータでも?
Jaime Hablutzel、2011年

101
flush()は、INSERT、UPDATEなどのSQL命令をデータベースに送信します。COMMITを送信しないため、flush()の後に例外がある場合でも、完全にロールバックできます。
フラビオ2011年

17
DBをロールバックすることはできますが、自動インクリメントされた「バージョン」、自動生成されたIDなど、オブジェクトへの変更はロールバックされません。さらに、ロールバック後にエンティティマネージャーは閉じられます。オブジェクトを別のセッションに「マージ」しようとすると、特に自動インクリメントされる「バージョン」がOptimisticLockExceptionを引き起こす可能性があることに注意してください。
ピーター・デイビス

11
副作用のトリガーとは別に、flush()を使用するもう1つの理由は、JPQL / HQLを使用して(たとえば、テストで)データベース内の操作の効果を読み取ることができるようにする場合です。JPAはこれらのクエリを実行するときにキャッシュされたデータを使用できないため、実際にDBにあるものだけが読み取られます。
sleske 2011

2

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

使用上の注意


1

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

はい、必要以上に長い期間データベースにロックを保持する可能性があります。

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.