NHibernate - 查询在保存新实体后错过了查询缓存

时间:2013-01-13 00:33:06

标签: c# nhibernate fluent-nhibernate linq-to-nhibernate

我有NHibernate(NHibernate.LinqFluent NHibernate)设置了查询缓存。一切正常,直到我做session.Save(new Widget())(即SQL INSERT)。在此之后,该类型Widget上的所有查询都会错过查询缓存。其他实体类型的查询缓存得很好。

using (ISession session = MySessionFactory.OpenSession())
{
    using (var transaction = session.BeginTransaction())
    {
        // this INSERT screws things up
        var widget = new Widget {Name = "Foo"};
        session.Save(widget);

        var query = (from w in session.Query<Widget>().Cacheable()
                     where w.Name == "Bar"
                     select w);

        var fetched1 = query.FirstOrDefault();
        var fetched2 = query.FirstOrDefault(); // miss?!

        transaction.Commit();
    }
}

如果我开始新的Transaction,则问题仍然存在。如果我开始新的Session,问题就会消失。这似乎有点奇怪,因为我的理解是每个SessionFactory(不是Session)重置二级缓存。

我认为这不重要,但我使用的是HashtableCacheProvider,因为我现在正在测试。

1 个答案:

答案 0 :(得分:6)

您所描述的行为是正确的more here

  

更新时间戳缓存在您提交之前不会更新   交易!这是为了确保您不会读取“未提交的内容”   值“来自缓存。

每当我们在Cache中获得的type发生变化时 - 缓存数据都是陈旧的...直到提交完整的事务。

想象一下,您已缓存此过滤器的结果:

 var query = (from w in session.Query<Widget>().Cacheable()
  where w.Name == "B*" // all names starting with B
  select w);

稍后会添加新的Widget:

var widget = new Widget {Name = "Brigitte"};
session.Save(widget);
// explicit Flush is not needed, 
// but then, until Commit(), query will never return Brigitte
session.Flush(); // to immediately execute INSERT

如果查询仍然被缓存,Brigitte将永远不会出现......

在Transaction中,使用FirstOrDefault()的查询会立即执行 - 写操作可能会等待Flush on Commit。

由于Transaction,所有包含的操作(insert,udpate,select)都无法从缓存中获益,因为只有Transaction作为批处理才有意义。因此,在调用commit之前,不能使用缓存。

可以在此处找到许多详细且非常有用的信息:First and Second Level caching in NHibernate

  

每当写入一个表时,时间戳缓存都会更新,但是会以一种棘手的方式:

     
      
  • 当我们执行实际写入时,我们会在将来的某个位置写入缓存中的值。所以所有的查询都达到了   缓存现在找不到它,然后点击DB获取新数据。   由于我们处于交易中,他们会等到我们   完成交易。如果我们使用低隔离级别,和   另一个线程/机器试图将旧结果放回到   缓存,它不会成立,因为更新时间戳是进入的   未来。
  •   
  • 当我们对事务执行提交时,我们使用当前值更新时间戳缓存。
  •