即使ORDER BY子句不同,NHibernate也会检索缓存的查询结果
我看到了NHibernate中的一个bug,它带有查询缓存和ORDERBY子句 当我运行以下查询时即使ORDER BY子句不同,NHibernate也会检索缓存的查询结果,nhibernate,sql-order-by,query-cache,Nhibernate,Sql Order By,Query Cache,我看到了NHibernate中的一个bug,它带有查询缓存和ORDERBY子句 当我运行以下查询时 SELECT this_.Id as y0_, this_.Name as y1_ FROM Products this_ WHERE this_.IsActive = 1 ORDER BY this_.IsPremium desc 。。。如果我打开了查询缓存,并告诉NHibernate缓存此查询(使用例如条件.SetCacheable(tru
SELECT this_.Id as y0_,
this_.Name as y1_
FROM Products this_
WHERE this_.IsActive = 1
ORDER BY this_.IsPremium desc
。。。如果我打开了查询缓存,并告诉NHibernate缓存此查询(使用例如条件.SetCacheable(true)
),则NHibernate会成功缓存其结果
不幸的是,正如Wonder告诉我的,NHibernate在运行此查询时也使用缓存的查询结果:
SELECT this_.Id as y0_,
this_.Name as y1_
FROM Products this_
WHERE this_.IsActive = 1
ORDER BY this_.IsPremium desc,
this_.Name
有人能解释一下为什么或者给我指一些关于这个“特性”的深入文档吗?或者,更好的是,是否有人有解决该问题的解决方案?NHibernate使用一级缓存(通过身份映射实现)来缓存您查询的每个对象。NHibernate处理单个实体,即使查询对象列表也是如此 让我解释一下:
您查询是否执行此查询并尝试获取id为1的实体:
session.get<SomeEntity>(1);
session.get(1);
NHibernate将检查缓存,看看它是否已经包含id 1。如果是这样,缓存对象将被返回,并且它不会运行查询。如果没有,则选择记录执行查询,将其放入缓存并返回给您。如果您再次执行查询,它将被缓存,并且对象将在不使用新查询的情况下返回
现在,如果您查询如下列表:
session.QueryOver<SomeEntity>().List();
session.QueryOver().List();
nhibernate不知道将获取哪个id,因此它将查询所有记录并逐个检查缓存中的结果,即使您运行了两次查询。假设数据库中有2条记录(id 1和2)。当缓存仍然为空时,使用查询获取它们。这两条记录都会被提取、放入缓存并返回给您。现在,插入记录3、4和5,在执行此操作时,还将更新记录1。现在,如果再次运行查询,它将读取所有5条记录,但现在还将缓存记录3、4和5。您将得到一个包含5个对象的列表,其中3、4、5是刚读取的对象,但返回缓存版本的1和2。您将无法获得id 1的更新版本
因此,回答您的问题:通过更改顺序并不重要。您的查询将生成一组记录,这些记录将逐个根据缓存进行检查,如果其中一个记录已经存在,则返回该缓存版本
您的问题的解决方案可能是:
- 使用session.Refresh(obj);如果您知道哪些已更新
- 从会话中逐出部分或所有实体(这意味着它们将被抛出缓存,并可以通过查询重新蚀刻)。注意:如果您将其逐出,更改的内容将不会保存
- 您可以使用无状态会话,正如无状态名称所示,它没有缓存李>
您可以查询是否执行此查询并尝试获取id为1的实体:
session.get<SomeEntity>(1);
session.get(1);
NHibernate将检查缓存,以查看它是否已经包含id 1。如果是这样,缓存对象将被返回,并且它不会运行查询。如果没有,则选择记录执行查询,将其放入缓存并返回给您。如果您再次执行查询,它将被缓存,并且对象将在不使用新查询的情况下返回
现在,如果您查询如下列表:
session.QueryOver<SomeEntity>().List();
session.QueryOver().List();
nhibernate不知道将获取哪个id,因此它将查询所有记录并逐个检查缓存中的结果,即使您运行了两次查询。假设数据库中有2条记录(id 1和2)。当缓存仍然为空时,使用查询获取它们。这两条记录都会被提取、放入缓存并返回给您。现在,插入记录3、4和5,在执行此操作时,还将更新记录1。现在,如果再次运行查询,它将读取所有5条记录,但现在还将缓存记录3、4和5。您将得到一个包含5个对象的列表,其中3、4、5是刚读取的对象,但返回缓存版本的1和2。您将无法获得id 1的更新版本
因此,回答您的问题:通过更改顺序并不重要。您的查询将生成一组记录,这些记录将逐个根据缓存进行检查,如果其中一个记录已经存在,则返回该缓存版本
您的问题的解决方案可能是:
- 使用session.Refresh(obj);如果您知道哪些已更新
- 从会话中逐出部分或所有实体(这意味着它们将被抛出缓存,并可以通过查询重新蚀刻)。注意:如果您将其逐出,更改的内容将不会保存
- 您可以使用无状态会话,正如无状态名称所示,它没有缓存李>