2012-05-10 3 views
7

HQLクエリが情報を取得する場所を理解する上で問題があります。私のプロジェクトは異なるスレッドを使用しており、各スレッドはデータベースに対して読み書きを行っています。スレッドはセッションオブジェクトを共有しません。代わりに、セッションを作成するHibernateUtilクラスを使用しています。Hibernate HQLはセッションキャッシュにのみヒットする

最近まで、私は書いた後だけセッションを終了しましたが、読んだ後では終了しませんでした。オブジェクトへの変更は、データベースではなく、で他のスレッド(書き込みに使用されたものとは異なるセッションオブジェクト)で読み取ると直ちに表示されます。読み書きは常に異なるスレッド上で起こりました。これは異なるセッションオブジェクトと異なるセッションキャッシュを意味します。

私はいつもCriteriaの代わりにHQLを使用して、セッションキャッシュではなくデータベース(またはセカンドレベルのキャッシュ)をターゲットにしていたと思いますが、コードをデバッグするときにHQLが探していたことがわかりました。セッションキャッシュ内のオブジェクトを取得し、古くなった古いオブジェクトを取得しました。

HQLは常にデータベースを対象としていると仮定して間違っていましたか?または少なくとも第2レベルのキャッシュ?

PS:私はSessionFactoryオブジェクトを1つだけ使用しています。

答えて

7

Hibernateには、エンティティキャッシュとクエリキャッシュという異なる概念があります。エンティティキャッシュとは、セッションキャッシュ(および使用可能な場合は第2レベルキャッシュ)のことです。

クエリキャッシングが有効になっていない(デフォルトではそうではない)と仮定すると、HQLはデータベースに対して実行されているはずです。これにより、クエリに一致するエンティティのIDが返されます。それらのエンティティがセッションキャッシュにすでに存在していた場合、Hibernateはデータベースからそれらを再構築するのではなく、それらを返すでしょう。あなたのセッションにそれらの古いコピーがある場合(別のセッションがデータベースを更新したため)、それが問題です。

主にその理由から、長寿命セッションの使用をお勧めします。セッションの有効期間を、実行しようとしている特定の作業単位に制限し、それを閉じます。これを行うにはパフォーマンスの低下がほとんどまたはまったくありません(データベース接続プールを使用していると仮定します)。また、失効したエンティティを取得しないようにするには、Session.clear()を呼び出すことができますが、予期しないパフォーマンスの副作用が発生する可能性があります。

+0

私のセッションオブジェクトが初めてデータベースをターゲットとするHQLクエリを実行するときです。結果はセッションキャッシュに格納されます。 2回目に同じHQLクエリを実行すると、データベースを対象とするのではなくキャッシュが読み込まれます。これがデフォルト動作です。私はこれを正しく理解していますか? ** ps:**実際、各読み書き後のセッションを閉じます(短いセッションの 'Session'オブジェクト)が私の問題を解決します。 – alegen

+4

@alegen:HQLは毎回データベース*に対して実行されますが、そのクエリの最終結果であるJavaオブジェクトはセッションキャッシュから取得される可能性があります。これがデフォルト動作です。 – skaffman

+1

あなたは素晴らしい一日を過ごしています!あなたの答えをありがとう:) – alegen