4

JSFプロジェクトの背後でHibernateを使用しています。

メインページには、オブジェクトのリストを表すデータテーブルがあります。

Hibernateを使用して、オブジェクト(データテーブルにあります)のプロパティを正常に更新しました。更新後、「xxx?faces-redirect=true」を使用してリダイレクトすることでページが更新されます。「重複フォーム送信」のような問題を回避するために、ページをリダイレクトします。

次に、F5キーを数回押すと、更新されたオブジェクトの古いプロパティ値がページに戻る可能性があります。

私が理解しているように、これはHibernateセッションの問題です。使用後、すべてのセッションをすぐに閉じると、この問題は発生しません。ただし、遅延フェッチ戦略のため、トランザクション後にセッションを閉じることができません。

簡単に言うと、休止状態は、正常に更新されていても、オブジェクトの古い値をもたらす可能性があります。どうすればそのような問題を回避できますか?

ps:Hibernateのキャッシュメカニズムについて疑っていましたが、以下を使用して第1レベルと第2レベルのキャッシュを無効にしました。

<property name="hibernate.cache.use_query_cache">false</property>
<property name="hibernate.use_second_level_cache">false</property>

しかし、それも機能しませんでした。

更新:@Johannaの応答後、セッションインスタンスのIDを制御し、HibernateUtilクラスがほとんどの場合別のセッションを返すか、新しいセッションを開くことに注意しました。getSession()メソッドは次のとおりです。

public static Session getSession(){
    Session se = HibernateUtil.session.get();
    if(se == null)
    {
        se = sessionFactory.openSession();
        HibernateUtil.session.set(se);
    }
    return se;
}

セッションができたら、そのセッションでリストや更新などすべてを行うと思っていました。getSession()メソッドで必要なコントロールを作成するためです。どこで間違えますか?

4

1 に答える 1

4

use_query_cacheもuse_second_level_cacheも、第1レベルのキャッシュを無効にすることはできません。第1レベルのキャッシュは常にオンになっています。

本当に第1レベルのキャッシュを使用したくない場合は、Sessionの代わりにStatelessSessionを使用する必要があります。ただし、StatelessSessionの機能は少なく、必要なメソッドの一部が欠落している可能性があります。

第1レベルのキャッシュからいくつかのオブジェクトのみを削除する場合は、Session.evict()を使用できます。

それにもかかわらず、Hibernateがなぜ古い価値をあなたに提示するのか疑問に思います。各データベースエンティティのセッションにインスタンスが1つしかない場合(つまり、更新するオブジェクトのインスタンスがリストに表示されているものと同じインスタンスである場合)、これは発生しないはずです。2つの異なるインスタンスを使用する場合、通常、Hibernateは古い値を提示します(2つのSessionインスタンスを使用する場合、1つはリスト用、もう1つは更新用であり、リスト内の古い値も取得します)。したがって、アプリケーションを修正するときに、オブジェクトを削除する必要はないかもしれません。

更新後の編集:短いコードレットでは、シングルユーザーとしてアプリケーションを使用した場合にエラーが発生する理由がわかりません。

ただし、一般的には、JSFを使用しているため、多くのユーザーが使用できるWebプロジェクトである可能性があります。

Hibernate Sessionオブジェクトはスレッド保存されません。つまり、異なるユーザーが同時に使用する場合はおそらく機能しません。各ユーザーには、独自のセッションオブジェクトが必要です。したがって、HibernateセッションインスタンスをHttpセッションインスタンスに保存できます(その場合でも、最初のリクエストからの応答が到着する前にユーザーがボタンを2回押す場合に備えて、「同期」メソッド(またはオブジェクト)を使用する必要があります)。 )。

2番目の編集:この質問と同じ問題があると思います。

おそらく、引用された質問のDAOのような場所からコードをコピーしたのでしょう。コードをどこからでもコピーしたHibernateUtilクラスは、HibernateセッションをThreadLocalオブジェクトに格納していると思います。つまり、1つのHibernateセッションが1つのスレッドにバインドされています。

しかし、あなたはWebプロジェクトを行っています。そこで、1つのHibernateセッションを1つのユーザー(またはブラウザー)、つまり1つのHttpセッションにバインドする必要があります。ただし、1つのhttpセッションからの要求がどのスレッドで処理されるかはわかりません。したがって、ソリューションでは、同じHttpセッションが異なるHibernateセッションを取得するか、異なるHttpセッションが同じHibernateセッションを取得する可能性があります。これは、Httpサーバーによって異なります。

解決策:HibernateセッションをHttpセッションに入れます(そしてThreadLocalオブジェクトを使用しないでください)。Httpセッションオブジェクトを取得しHttpServletRequest.getSession()、Hibernateセッションおよびその他のHttpセッション関連データを設定できますHttpSession.getAttribute()HttpSession.setAttribute()

于 2012-04-17T15:46:24.180 に答える