Hibernate がセッションをフラッシュするとき、セッション内のどのオブジェクトがダーティであるかをどのように判断するのでしょうか?
質問
Hibernate についての私の理解は、オブジェクトが DB からロードされるとセッションに追加されるということです。設定に応じて、さまざまな時点でセッションがフラッシュされます。この時点で、変更されたオブジェクトがデータベースに書き込まれます。
Hibernate はどのオブジェクトが「ダーティ」であり、書き込む必要があるかをどのように判断するのでしょうか?
Hibernate によって生成されたプロキシはフィールドへの割り当てをインターセプトし、そのオブジェクトをセッション内のダーティ リストに追加しますか?
それとも、Hibernate はセッション内の各オブジェクトを調べて、オブジェクトの元の状態と比較しますか?
それとも全く別のものでしょうか?
解決
Hibernate はバイトコード生成 (CGLIB) を使用します/使用できるので、セッターを呼び出すと (またはフィールド afaict に代入すると) すぐにフィールドがダーティであることがわかります。
これにより、そのフィールド/オブジェクトは直ちにダーティとしてマークされますが、フラッシュ中にダーティ チェックが必要なオブジェクトの数は減りません。それは実装に影響を与えるだけです org.hibernate.engine.EntityEntry.requiresDirtyCheck()
. 。それ まだ フィールドごとに比較して汚れをチェックします。
私が上記のことを述べたのは、ソース コード (3.2.6GA) を最近調べた結果に基づいており、それに加えて信憑性があればとのことです。興味深い点は次のとおりです。
SessionImpl.flush()
を引き起こしますonFlush()
イベント。SessionImpl.list()
電話をかけるautoFlushIfRequired()
それはonAutoFlush()
イベント。(注目のテーブル上)。つまり、クエリはフラッシュを呼び出すことができます。興味深いことに、トランザクションが存在しない場合、フラッシュは発生しません。- どちらのイベントも最終的には
AbstractFlushingEventListener.flushEverythingToExecutions()
, 、最終的には(他の興味深い場所の中でも)flushEntities()
. - これはセッション内のすべてのエンティティをループします (
source.getPersistenceContext().getEntityEntries()
) 電話をかけるDefaultFlushEntityEventListener.onFlushEntity()
. - 最終的に行き着くのは、
dirtyCheck()
. 。このメソッドは CGLIB ダーティ フラグに関していくつかの最適化を行いますが、依然としてすべてのエンティティをループすることになります。
他のヒント
Hibernate は、セッションにロードされる各オブジェクトの状態のスナップショットを取得します。フラッシュ時に、セッション内の各オブジェクトが対応するスナップショットと比較され、どのオブジェクトがダーティであるかを判断します。SQL ステートメントは必要に応じて発行され、スナップショットは (クリーンになった) Session オブジェクトの状態を反映するように更新されます。
org.hibernate.event.def.def.defaultflushentityeventlistener.dirtycheckをご覧ください。セッションのすべての要素は、この方法に触れているかどうかを判断します。
Hibernate のデフォルトのダーティ チェック メカニズム 現在アタッチされているエンティティを走査し、すべてのプロパティを初期読み込み時間の値と照合します。
このプロセスは、次の図でわかりやすく視覚化できます。
これらの回答は不完全です (せいぜい、私はこの分野の専門家ではありません)。セッション内に hib man エンティティがある場合、それに対して何もする必要はありませんが、それに対して save() を呼び出したときに更新を発行することができます。いつ?別のセッションがload()とsave()の間でそのオブジェクトを更新したとき。これが私の例です: クライアントが値を変更していないにもかかわらず、hibernate はダーティ フラグを設定します (そして更新を発行します)。