2

Fluent NHibernate で第 2 レベルのキャッシュ プロバイダー SysCache2 を使用し、標準的な流暢な構成 (一般的なアドバイスのようにクエリ キャッシュを有効にする) を使用し、テーブル ベースの依存関係を通常の方法で定義しています。

流暢:

config.Cache(c => c
 .ProviderClass<NHibernate.Caches.SysCache2.SysCacheProvider>()
 .UseQueryCache()
 .UseSecondLevelCache()
 .UseMinimalPuts()

)

Web.Config:

  <cacheRegion name="User" relativeExpiration="7200">
<dependencies>
  <tables>
    <add name="User" databaseEntryName="OldClient" tableName="tbl_users" />
  </tables>
</dependencies>

ユーザー マッピング:

public class UserMap : ClassMap<User>
{
    public UserMap()
    {
        Table("Users");
        ....
        // caching
        Cache.IncludeAll().ReadWrite().Region("Users");
    }
}

単一のリクエストに対してすべてが期待どおりに実行されます。つまり、次のようになります。

Session<User>.Get()

NHibernate が IDでキャッシュする方法から予想されるとおりです。後続のリクエストはデータベースにヒットせず、データベース内のレコードを無効にするとエンティティが無効になり、次のリクエスト中に後続の SQL 呼び出しが発生します。大丈夫。

問題はクエリのキャッシュにあります。最初の例では、すべて正常に動作します。次のような呼び出しを実行します。

Session<User>.Query(item => item.Active == true) 

期待どおりの SQL 呼び出しになります (SELECT * FROM Users WHERE Active = true)。その後の実行では、SQL は発生しません。偉大な。クエリ セットの 1 つのレコードがデータベースで変更されるまで。同じクエリを実行すると、SELECT N+1 になります。

SELECT * FROM Users WHERE ID = 1
SELECT * FROM Users WHERE ID = 2
SELECT * FROM Users WHERE ID = 3
SELECT * FROM Users WHERE ID = 4
...

解決策はありませんが、他の場所でこれへの参照を見つけました:

StackOverflow - NHibernate キャッシュ フェッチされた子コレクションを作成するにはどうすればよいですか? 「もう 1 つのポイント」セクションを参照してください

最後に「エンティティもキャッシュされる」ことを保証するAyende Caching Strategiesに言及

現時点でこれを回避できる唯一の方法は、リクエストごとにクエリキャッシュをクリアすることです。これにより、ほとんど役に立たなくなります。個々のレコードだけでなく、エンティティが無効化されたときに、クエリ キャッシュが特定のエンティティのすべてをクリアするために必要なこと。

何か案は?

4

1 に答える 1

3

あなたが投稿した両方のリンクによると、クエリ キャッシュはクエリの結果の ID をキャッシュし、エンティティを 1 つずつフェッチし始めます。キャッシュにエンティティがある場合は、うまくいきませんが、そうでない場合は、多くの選択が行われます。

この時点で、選択しているエンティティは第 2 レベルのキャッシュにない (もう?) と思います。テーブルベースの依存関係を使用したことはありません。コマンドベースの依存関係を使用しています。エンティティが無効としてマークされている場合、キャッシュ領域全体ではなく、このキャッシュされたエンティティのみがキャッシュからスローされることをテストしました。

構成が正しいことを確認してください。おそらく、第 2 レベルのキャッシュにヒットしていると思われる場合、実際にはセッション キャッシュにヒットしているのではないでしょうか? キャッシュが異なるセッション間で機能していることをテストしていることを確認してください。

いずれにせよ、NHibernate の DEBUG レベルのログを調べて、2 番目のレベルのキャッシュで実際に何が起こっているかを確認することをお勧めします。そこでは、すべてのキャッシュ ヒット/ミスを確認できます。もう 1 つのヒントは、構成で generate_statistics フラグを有効にすることです。流暢:

config.ExposeConfiguration(c => c.SetProperty("generate_statistics", "true"));

Session.SessionFactory.Statistics.SecondLevelCacheMissCountこの後、やなどのセッション ファクトリで興味深いデータにアクセスできますSession.SessionFactory.Statistics.SecondLevelCacheHitCount。これら 2 つの方法を組み合わせることで、問題の原因を特定できるはずです。

于 2013-02-07T10:21:41.367 に答える