n休眠第二级缓存在查询时不起作用

本文关键字:存在 缓存 查询 不起作用 二级 休眠 | 更新日期: 2023-09-27 18:34:13

我有以下问题。我已经在nHibernate(使用Postgres(上启用了第二级缓存系统,如下所示配置

cfg.SessionFactory().Caching.Through<RtMemoryCacheProvider>().WithDefaultExpiration(28800);

只启用实体缓存,因为此时我不需要查询缓存。

在我的实体中,这是我的设置(它们有些是读写的,有些是只读的,此时可以设置为只读(

<id name="StudentID" access="property" column="`StudentID`">
  <generator class="native" />
</id>
<property name="Name" column="`Name`" >
<property name="Address" column="`Address`" />
<property name="IsActive" column="`IsActive`" />
<property name="DateCreated" column="`DateCreated`" />
<property name="DateLastUpdated" column="`DateLastUpdated`" />
<property name="LastUpdatedBy" column="`LastUpdatedBy`" />
<set name="Projects" inverse="true" mutable="false">
  <cache usage="read-only"/>
  <key column="`StudentID`" />
  <one-to-many class="Project" />
</set>
<set name="Classes" inverse="true" mutable="false">
  <cache usage="nonstrict-read-write"/>
  <key column="`StudentID`" />
  <one-to-many class="Class" />
</set>
<set name="Books" inverse="true" mutable="false">
  <cache usage="nonstrict-read-write"/>
  <key column="`StudentID`" />
  <one-to-many class="Book" />
</set>
</class>

在对我的解决方案进行单元测试时 - 我首先预取学生列表,然后尝试生成缓存命中

public bool PreLoadStudents()
{
    using (ISession session = NHibernateHelper.OpenSession())
    {
        IList<Student> results = session.QueryOver<Student>()
                                 .Fetch(d => d.Projects).Eager
                                 .Fetch(d => d.Classes).Eager
                                 .Fetch(d => d.Books).Eager
                                 .TransformUsing(Transformers.DistinctRootEntity)
                                 .List<Student>();
     }
}
[Test]
public void GetByIdTest()
{
   bool bLoaded = testBLL.PreLoadStudents();
   var student1 = testBLL.GetByID("123");
   var student2 = testBLL.GetByID("123");
   long cacheHit = testBLL.GetSessionFactory().Statistics.SecondLevelCacheHitCount;
   Assert.That(cacheHit,Is.EqualTo(2));    
}

我已经尝试了两种不同的"GetByID"实现,其中一个使用约定"get"方法,另一个使用查询方法与 fetch 语句类似到预加载学生学生方法。

在"get"方法的情况下,缓存命中和测试通过。在"查询结束"的情况下,不会发生缓存命中或未命中,而是执行了 2 个查询。

这是我使用"Get"方法用于"GetByID"方法

的代码
var student = session.Get<Student>(studentId); 

我不喜欢这种方法,因为我无法获取延迟加载的子集合

这是我使用"QueryOver"方法用于"GetByID"方法的代码

 var student = session.QueryOver<Student>()
                                          .Where(d => d.studentId == currentStudentId)
                                          .Fetch(d => d.Projects).Eager
                                          .Fetch(d => d.Classes).Eager
                                          .Fetch(d => d.Books).Eager
                                          .SingleOrDefault();

关于为什么"get"方法生成命中而查询方法没有的任何想法?

n休眠第二级缓存在查询时不起作用

在阅读并做了一些实验测试之后,这是我的问题出现的解决方案。

我最初的问题 - 关于为什么"get"方法产生命中而查询方法没有的任何想法?是一个错误的问题,原因如下:

  1. nHibernate中的二级缓存(L2(缓存实体的值
  2. nHibernate中的查询缓存缓存搜索结果的索引

因此

  1. Get 允许我们在知道 id 的情况下快速检索实体。如果我们不知道 ID,那么我们需要执行一个将命中的查询数据库(如果以前未运行过(。另一种方法是从缓存加载所有内容,然后在缓存上运行 LINQ。
  2. 查询
  3. 结束允许我们将查询结果存储在可以从二级缓存填充的查询缓存中。

经验 教训

    如果要缓存查询,请同时打开 L2 缓存和查询缓存
  1. ,没有 L2 的查询缓存可能不会提高太多性能
  2. L2 只能通过缓存查询或通过 GET 访问

二级缓存仅在您有事务时才有效,这也是解决查询的良好做法。

using (ISession session = NHibernateHelper.OpenSession())
using (ITransaction tx = session.BeginTransaction())
{
    IList<Student> results = session.QueryOver<Student>()
                             .Fetch(d => d.Projects).Eager
                             .Fetch(d => d.Classes).Eager
                             .Fetch(d => d.Books).Eager
                             .TransformUsing(Transformers.DistinctRootEntity)
                             .List<Student>();
    tx.Commit();
}