6

我有 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,因为我现在只是在测试。

4

1 回答 1

6

您描述的行为是正确的更多here

在您提交事务之前,更新时间戳缓存不会更新!这是为了确保您不会从缓存中读取“未提交的值”。

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

想象一下,你已经缓存了这个过滤器的结果:

 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。

由于事务,所有包含的操作(插入、更新、选择)都无法从缓存中受益,因为只有事务作为批处理才有意义。所以在调用 commit 之前,不能使用缓存。

可以在此处找到许多详细且非常有用的信息:NHibernate 中的一级和二级缓存

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

  • 当我们执行实际写入时,我们将一个未来某处的值写入缓存。所以现在所有命中缓存的查询都不会找到它,然后命中数据库获取新数据。由于我们处于交易中间,他们会等到我们完成交易。如果我们使用低隔离级别,并且另一个线程/机器尝试将旧结果放回缓存中,它不会保留,因为更新时间戳是未来的。
  • 当我们对事务执行提交时,我们用当前值更新时间戳缓存。
于 2013-01-13T07:10:30.323 回答