即使ORDER BY子句不同,NHibernate也会检索缓存的查询结果

时间:2012-05-23 17:49:27

标签: nhibernate sql-order-by query-cache

我正在使用查询缓存和ORDER BY子句看到NHibernate中的错误...

当我运行以下查询时...

SELECT this_.Id          as y0_,
       this_.Name        as y1_
FROM   Products this_
WHERE  this_.IsActive = 1
ORDER BY this_.IsPremium desc

...如果我打开了查询缓存,NHibernate会成功缓存其结果,并告诉它缓存此查询(使用例如criteria.SetCacheable(true))。

不幸的是,正如精彩的NHProf告诉我的那样,NHibernate在运行此查询时也会使用缓存的查询结果:

SELECT this_.Id          as y0_,
       this_.Name        as y1_
FROM   Products this_
WHERE  this_.IsActive = 1
ORDER BY this_.IsPremium desc,
         this_.Name

任何人都可以解释原因或指出我对这个“功能”的一些深入文档吗?或者,更好的是,是否有人对此问题有解决方案

1 个答案:

答案 0 :(得分:0)

NHibernate使用第一级缓存(由身份映射实现)来缓存您查询的每个对象。 NHibernate适用于单个实体,即使您查询对象列表也是如此。

让我解释一些事情:
您查询是否执行此查询并尝试获取ID为1的实体:

session.get<SomeEntity>(1);

NHibernate将检查缓存以查看它是否已包含id 1。如果是这样,将返回缓存的对象,它将不会运行查询。如果没有,则执行查询,选择记录,将其放入缓存并将其返回给您。如果再次执行查询,则会对其进行高速缓存,并在没有新查询的情况下返回对象。

现在,如果您查询这样的列表:

session.QueryOver<SomeEntity>().List();

nhibernate不知道将获取哪个id,因此它将查询所有记录并逐个检查结果,即使您运行查询两次。假设您的数据库中有2条记录(标识1和2)。当缓存仍为空时,您可以使用查询获取它们。两个记录都被提取,放入缓存并返回给您。现在你插入记录3,4和5,当你在它的时候,你也会更新记录1。现在,如果再次运行查询,它将读取所有5条记录,但现在也会缓存记录3,4和5。您将获得一个包含5个对象的列表,其中3,4,5是刚刚读取的对象,但返回的缓存版本为1和2。你不会得到id 1的更新版本。

因此回答你的问题:改变顺序并不重要。您的查询将导致一组记录逐个检查缓存,如果其中一个已经存在,则返回此缓存版本。

解决问题的方法可能是:

  • 使用session.Refresh(obj);如果您知道哪些已更新。
  • 从会话中逐出某些或所有实体(这意味着它们将被抛出缓存并可以通过查询重新获取)。注意:如果你逐出它们,就不会保存更改。
  • 你可以使用无状态会话,正如无状态名称所暗示的那样 - 没有缓存。