これまでのところ、私の好みはEntityManagerのmerge()
を常に使用して挿入と更新の両方を処理することでした。しかし、更新/挿入の前にマージが追加の選択クエリを実行して、レコードがデータベースに存在しないことを確認することにも気付きました。
現在、データベースへの大量の(一括)挿入を必要とするプロジェクトに取り組んでいます。パフォーマンスの観点から、永続化するオブジェクトの新しいインスタンスを常に作成していることを絶対に知っているシナリオで、マージの代わりに永続化を使用することは意味がありますか?
merge
で十分な場合にpersist
を使用するのは得策ではありません-merge
はかなり多くの作業を行います。トピックは StackOverflowで説明 以前、および この記事 は違いを詳細に説明し、わかりやすいようにニースのフロー図を示しています。
あなたが言ったように、私は間違いなくpersist persist()
に行きます:
(...)永続化するオブジェクトの新しいインスタンスを常に作成していることは絶対に知っています(...)
それがこの方法のすべてです-エンティティが既に存在する場合に保護します(そしてトランザクションをロールバックします)。
割り当てられたジェネレータを使用している場合、 merge
の代わりにpersist
を使用すると、冗長なSQLステートメントが発生する可能性があります 。したがって、パフォーマンスに影響します。
また、管理対象エンティティはHibernateによって自動的に管理され、その状態は ダーティチェックメカニズム によってデータベースレコードと同期されるため、 管理対象エンティティのマージの呼び出し も誤りです。 永続コンテキストのフラッシュ 。
これがすべてどのように機能するかを理解するには、まずHibernateが開発者の考え方をSQLステートメントから エンティティ状態遷移 にシフトすることを知っておく必要があります。
エンティティがHibernateによってアクティブに管理されると、すべての変更が自動的にデータベースに伝播されます。
Hibernateは現在接続されているエンティティを監視します。ただし、エンティティが管理対象になるには、適切なエンティティ状態である必要があります。
まず、すべてのエンティティの状態を定義する必要があります。
新規(一時的)
Hibernate Session
(別名Persistence Context
)に関連付けられておらず、データベーステーブル行にマッピングされていない新しく作成されたオブジェクトは、New(Transient)状態にあると見なされます。
永続化するには、EntityManager#persist
メソッドを明示的に呼び出すか、推移的な永続化メカニズムを利用する必要があります。
永続的(管理対象)
永続エンティティはデータベーステーブルの行に関連付けられており、現在実行中の永続コンテキストによって管理されています。そのようなエンティティに加えられた変更はすべて検出され、データベースに伝播されます(セッションフラッシュ時間中)。 Hibernateでは、INSERT/UPDATE/DELETEステートメントを実行する必要がなくなりました。 Hibernateは transactional write-behind 作業スタイルを採用しており、現在のSession
フラッシュ時間中の最後の責任ある瞬間に変更が同期されます。
戸建
現在実行中の永続コンテキストが閉じられると、以前に管理されていたすべてのエンティティが切り離されます。連続した変更は追跡されなくなり、自動データベース同期は行われなくなります。
切り離されたエンティティをアクティブなHibernateセッションに関連付けるには、次のオプションのいずれかを選択できます。
再接続
Hibernate(JPA 2.1ではない)は、Session#updateメソッドによる再接続をサポートしています。 Hibernate Sessionは、特定のデータベース行に対して1つのEntityオブジェクトのみを関連付けることができます。これは、永続コンテキストがメモリ内キャッシュ(一次キャッシュ)として機能し、1つの値(エンティティ)のみが特定のキー(エンティティタイプとデータベース識別子)に関連付けられているためです。現在のHibernateセッションに既に関連付けられている(同じデータベース行に一致する)他のJVMオブジェクトがない場合にのみ、エンティティを再接続できます。
マージ
マージにより、切り離されたエンティティの状態(ソース)が管理対象エンティティのインスタンス(宛先)にコピーされます。マージするエンティティに現在のセッションに同等のエンティティがない場合、データベースから取得されます。切り離されたオブジェクトインスタンスは、マージ操作の後でも切り離されたままになります。
削除しました
JPAは管理対象エンティティのみを削除することを要求していますが、Hibernateは分離されたエンティティを削除することもできます(ただし、Session#deleteメソッド呼び出しを使用する場合のみ)。削除されたエンティティは削除のみがスケジュールされ、実際のデータベースのDELETEステートメントはセッションのフラッシュ時に実行されます。
JPAの状態遷移をよりよく理解するために、次の図を視覚化できます。
または、Hibernate固有のAPIを使用する場合: