16

hibernateを使用するSpringFrameworkに基づくWebアプリケーションのコントローラーでこの例外が発生します。私はこれに対抗するために多くの方法を試みましたが、それを解決することができませんでした。

コントローラのメソッドではhandleRequestInternal、送信アクションがない限り、主に「読み取り」のためにデータベースに対して呼び出されます。私はSpring'sSessionを使用してきましたが、移動しましたがgetHibernateTemplate()、問題はまだ残っています。

基本的に、これはデータベースへの2回目の呼び出しで、この例外をスローします。あれは:

1)getEquipmentsByNumber(number) {最初に、プロパティのリストがあり、各プロパティに値のリストがある「番号」に基づいて、機器がDBからフェッチされます。これらの値(プリミティブオブジェクトの文字列)をループして変数に読み込みます)

2)getMaterialById(id){idに基づいてマテリアルをフェッチします}

2番目の呼び出しは、おそらく「フラッシュ」するセッションを行っていることを理解していますが、私はオブジェクトを「読み取っている」だけです。何も変更されていない場合、2番目の呼び出しがEquipmentプロパティで古いオブジェクト状態の例外をスローするのはなぜですか。 ?

ビューに渡すオブジェクトでLazyExceptionsが発生するため、呼び出し後にキャッシュをクリアできません。

私はこれを読みました: https ://forums.hibernate.org/viewtopic.php?f = 1&t = 996355&start = 0 しかし、提供された提案に基づいて問題を解決できませんでした。

この問題を解決するにはどうすればよいですか?任意のアイデアや考えをいただければ幸いです。

更新: 私が今テストしたのはgetEquipmentsByNumber()、プロパティのリストから変数を読み取った後の関数で、これを行うことです:getHibernateTemplate().flush();そして今、例外は、マテリアルをフェッチするための呼び出しではなく、この行にあります(つまりgetMaterialById(id))。

更新: flushを明示的に呼び出す前に、セッションキャッシュからオブジェクトを削除して、古いオブジェクトがキャッシュに残らないようにします。

getHibernateTemplate().evict(equipment);
getHibernateTemplate().flush();

さて、これを行った後、問題はDBからの次のフェッチに移りました。メソッドに同期済みのラベルを付け、内容を読み終えたらすぐにオブジェクトを削除する必要があると思います。あまり良く聞こえません。

更新: メソッドhandleRequestInternalを「同期」しました。エラーは消えました。もちろん、最善の解決策ではありませんが、何をすべきか!handleRequestInternal現在のセッションを閉じて、新しいセッションを開くことを試みました。ただし、アプリの他の部分が正しく機能しなくなる可能性があります。ThreadLocalどちらも機能しなかったものを使おうとしました。

4

4 に答える 4

6

データベースからオブジェクトを更新または削除していると思わせる何らかの方法で Hibernate を誤用しています。

そのため、呼び出すflush()と例外がスローされます。

1 つの可能性: サーブレットまたはコントローラーのメンバー フィールドを介して、セッションまたはエンティティを誤って「共有」しています。これが、「同期」によってエラーの症状が変わる主な理由です。簡単な解決策: これは絶対に行わないでください。セッションとエンティティは、このように動作するべきではありません。各リクエストは個別に処理される必要があります。

別の可能性: unsaved-value"int" PK フィールドのデフォルトは 0 です。有効な PK 値として本当に 0 を使用したい場合は、これらを代わりに「整数」として入力できる場合があります。

3 番目の提案: Hibernate Session を明示的に使用し、機能する単純で正しいコードの書き方を学び、Hibernate/Spring ライブラリの Java ソースをロードして、これらのライブラリが実際に何をしているかを読んで理解できるようにします。

于 2011-11-15T05:18:27.840 に答える
3

私もこの例外に苦労していましたが、オブジェクトにロックをかけても再発し続けたとき(そして、オブジェクトに触れている唯一のプロセスであることがわかっているテスト環境で)、括弧を付けることにしましたスタック トレースでは、当然の考慮事項です。

org.hibernate.StaleObjectStateException: 行が別のトランザクションによって更新または削除されました (または保存されていない値のマッピングが正しくありません): [com.rc.model.mexp.MerchantAccount#59132]

私たちの場合、マッピングが間違っていることが判明しました。データベース内のミディアムテキスト型である 1 つのフィールドのマッピングがtype="text"ありましたが、少なくとも特定の状況下では、Hibernate はそれを本当に嫌っているようです。このフィールドのマッピングから型指定を完全に削除し、問題は解決されました。

奇妙なことに、私たちの実稼働環境では、おそらく問題のあるマッピングが配置されているため、この例外は発生しません。なぜこれが考えられるのか、誰にも分かりますか?私たちは同じバージョンの MySQL を使用しています - "5.0.22-log" ("-log" が何を意味するのかわかりません) - dev と production 環境で。

于 2011-09-15T19:56:42.893 に答える
2

ここに3つの可能性があります(正確にはわかりませんが、どの種類の休止状態セッション処理を使用していますか)。次々に追加してテストします。

inverse=true親オブジェクトと子オブジェクトの間で双方向マッピングを使用して、親または子の変更が関係の反対側に適切に伝播されるようにします。

or列を使用した楽観的ロックのサポートを追加TimeStampVersion

結合クエリを使用して、オブジェクト グラフ [親 + 子] 全体を一緒に取得し、2 回目の呼び出しを完全に回避します。

最後に、何も機能しない場合にのみ: 親を再度ロードしId(すでに持っています)、変更されたデータを入力してから更新します。

人生は良くなる!:)

于 2010-11-05T07:10:17.547 に答える
0

この問題は私が経験したもので、ID によるルックアップを行っている場合、古い状態になる理由がないため、DAO/Hibernate 呼び出しで少し奇妙なことが起こっている必要がありますが、非常にイライラしていました。 、これはオブジェクトの単純なルックアップにすぎないためです。

まず、すべてのメソッドに注釈が付けられていることを確認してください@Transaction(required=true) // you'll have to look up the exact syntax

ただし、この例外は通常、取得元のセッションから切り離されたオブジェクトに変更を加えようとするとスローされます。多くの場合、これに対する解決策は単純ではなく、何が起こっているのかを正確に確認できるように、より多くのコードを投稿する必要があります。私の一般的な提案は@Service、単一のトランザクション内でこれらの種類のことを実行する を作成することです

于 2010-07-01T14:51:19.563 に答える