1

OpenSessionInView フィルターで Hibernate Spring MVC を使用しています。これが私たちが遭遇している問題です(疑似コード)

transaction 1 
load object foo
transaction 1 end

update foo's properties (not calling session.save or session.update but only foo's setters)

validate foo (using hibernate validator)
if validation fails ?
 go back to edit screen
 transaction 2 (read only)
 load form backing objects from db
 transaction 2 end
 go to view
else 
transaction 3 
session.update(foo)
transaction 3 end

私たちが抱えている問題は、検証が失敗した場合、foo が休止状態セッションで「ダーティ」とマークされていることです (OpenSessionInView を使用しているため、http 要求全体で 1 つのセッションしかありません)。 HQLクエリ)、セッションにダーティオブジェクトがあるかどうかをクエリチェックを実行する前に休止状態にし、fooが存在することを確認してそれをフラッシュし、トランザクション2がコミットされると、更新がデータベースに書き込まれます。問題は、それが読み取り専用のトランザクションであり、トランザクション 2 で foo が更新されなかったとしても、hibernate はどのトランザクションでどのオブジェクトが更新されたかを認識せず、そのトランザクションからオブジェクトのみをフラッシュしないことです。助言がありますか?誰かが以前に同様の問題に遭遇しましたか

更新: この投稿は、問題をさらに明らかにします: http://brian.pontarelli.com/2007/04/03/hibernate-pitfalls-part-2/

4

6 に答える 6

1

get on fooを実行して休止状態のセッションに入れ、他の場所で作成したオブジェクトに置き換えることができます。ただし、これを機能させるには、オブジェクトのすべてのIDを知って、IDがHibernateに対して正しく表示されるようにする必要があります。

于 2008-10-28T20:21:31.187 に答える
1

ここに設計上の問題があります。ORM はデータストアの透過的な抽象化だと思いますか、それともデータ操作ライブラリのセットだと思いますか? Hibernate は前者だと思います。存在する理由は、メモリ内オブジェクトの状態とデータベースの状態の区別を取り除くことです。2 つをこじ開けて別々に処理できる低レベルのメカニズムを提供しますが、そうすることで、Hibernate の多くの価値が失われます。

非常に簡単に言えば、Hibernate = データベースです。何かを持続させたくない場合は、持続オブジェクトを変更しないでください。

ドメイン オブジェクトを更新する前に、データを検証します。必ずドメイン オブジェクトも検証しますが、それは最後の防衛線です。永続オブジェクトで検証エラーが発生した場合は、例外を飲み込まないでください。防止しない限り、Hibernate は正しいことを行います。つまり、その場でセッションを閉じます。

于 2009-07-15T02:48:30.877 に答える
1

ここにはいくつかのオプションがあります。まず、セッションが開いているため、トランザクション 2 は実際には必要ありません。データベースからバッキング オブジェクトをロードするだけで、セッションのダーティ チェックを回避できます。もう 1 つのオプションは、取得後にセッションから foo を削除し、後で session.merge() を使用して変更を保存するときに再接続することです。

ハイバネートでは、内部で何が起こっているのかを正確に理解することが重要です。すべてのコミット境界で、変更が現在のトランザクションで行われたかどうかに関係なく、現在のセッションのオブジェクトへのすべての変更をフラッシュしようとします。これは、すでにセッションにあるオブジェクトに対して実際に session.update() を呼び出す必要がない方法です。

お役に立てれば

于 2008-10-31T17:44:40.403 に答える
0

Session.clear() や Session.evict() を使用するのはどうですか?

于 2008-11-15T22:00:10.937 に答える
0

サービス層を実装し、Spring の @Transactional アノテーションを見て、該当する場合はメソッドを @Transactional(readOnly=true) としてマークします。

フラッシュ モードはおそらく自動に設定されています。つまり、DB コミットがいつ発生するかを実際に制御することはできません。

フラッシュモードを手動に設定することもできます。サービス/リポジトリは、指示されたときにのみデータベースとアプリを同期しようとします。

于 2009-11-24T18:57:41.113 に答える
0

フィルターで singleSession=false を設定するのはどうですか? これにより、操作が個別のセッションに分割される可能性があるため、第 1 レベルのキャッシュの問題に対処する必要がなくなります。それ以外の場合は、上記のユーザーが提案するように、オブジェクトを手動でデタッチ/アタッチすることをお勧めします。自動的にフラッシュされたくない場合は、セッションの FlushMode を変更することもできます (FlushMode.MANUAL)。

于 2008-11-29T07:46:35.853 に答える