如何让 NHibernate 缓存获取的子集合?

2024-05-04

我有一个相当简单的条件查询来获取子集合,如下所示:

var order = Session.CreateCriteria<Order>()
    .Add(Restrictions.Eq("Id", id))
    .SetFetchMode("Customer", FetchMode.Eager)
    .SetFetchMode("Products", FetchMode.Eager)
    .SetFetchMode("Products.Category", FetchMode.Eager)
    .SetCacheable(true)
    .UniqueResult<Order>();

使用 NH Prof,我已经验证这只需使用冷缓存到数据库进行一次往返(如预期);然而,在连续执行时,它只检索Order从缓存中获取,然后对图中的每个子实体使用 SELECT(N+1) 访问数据库,如下所示:

Cached query: SELECT ... FROM Order this_ left outer join Customer customer2 [...]
SELECT ... FROM Customer WHERE Id = 123;
SELECT ... FROM Products WHERE Id = 500;
SELECT ... FROM Products WHERE Id = 501;
...
SELECT ... FROM Categories WHERE Id = 3;

等等等等。显然它没有缓存whole查询或图形,仅根实体。第一个“缓存查询”行实际上包含所有join它应该的条件 - 它肯定会缓存查询本身正确,只是不是entities, 显然。

我已经使用 SysCache、SysCache2 甚至 HashTable 缓存提供程序尝试过此操作,并且我似乎总是得到相同的行为(NH 版本 3.2.0)。

谷歌搜索发现了一些古老的问题,例如:

  • NH-195:子集合未存储在二级缓存中 https://nhibernate.jira.com/browse/NH-195
  • SysCache 和 SysCache2 之间的奇怪差异 https://forum.hibernate.org/viewtopic.php?p=2368641#2368641
  • NHibernate – 谨防不当应用的缓存策略 http://ayende.com/blog/4046/nhibernate-beware-of-inadvisably-applied-caching-strategies(Ayende - 当然他只是费心提到什么not去做,而不是如何解决......)

然而,这些似乎早就被修复了,无论我使用哪个提供商,我都会遇到同样的不良行为。

我已经读过关于 SysCache 和 SysCache2 的 nhibernate.info 文档 http://nhibernate.info/doc/nhibernate-reference/caches.html#NHibernate.Caches.SysCache2我似乎没有遗漏任何东西。我尝试过添加cacheRegion线到Web.config文件中涉及查询的所有表,但它不会改变任何内容(而且据我所知,这些元素只是为了无效缓存,所以它们无论如何都不重要)。

所有这些超级老问题似乎都已得到解决/解决,我认为这是不可能的still是 NHibernate 中的一个错误,这一定是我做错了什么。但什么?

将 NHibernate 中的获取指令与二级缓存结合时,我需要做一些特别的事情吗?我在这里缺少什么?


我确实设法弄清楚了这一点,所以其他人终于可以得到直接的答案:

综上所述,我有一段时间对二级缓存和查询缓存的区别感到困惑;杰森的答案在技术上是正确的,但不知怎的,它并不适合我。我是这样解释的:

  • 查询缓存会跟踪哪些实体由查询发出。确实如此not缓存整个结果集。这相当于做一个Session.Load在延迟加载的实体上;它知道/预期存在但不跟踪any除非特别询问,否则它会实际加载其他信息real entity.

  • 二级缓存跟踪实际的data对于每个实体。当 NHibernate 需要通过 ID 加载任何实体时(凭借Session.Load, Session.Get、延迟加载关系,或者在上面的情况下,是缓存查询一部分的实体“引用”),它将首先在二级缓存中查找。

当然,事后看来,这是完全有道理的,但是当您听到“查询缓存”和“二级缓存”这两个术语在很多地方几乎可以互换使用时,这就不是那么明显了。

本质上,您需要配置两组(每组两个设置)才能看到查询缓存的预期结果:

1. 启用两个缓存

在 XML 配置中,这意味着添加以下两行:

<property name="cache.use_second_level_cache">true</property>
<property name="cache.use_query_cache" >true</property>

在 Fluent NHibernate 中,是这样的:

.Cache(c => c
    .UseQueryCache()
    .UseSecondLevelCache()
    .ProviderClass<SysCacheProvider>())

请注意UseSecondLevelCache上面因为(在发布本文时)它是never上提到的Fluent NHibernate wiki 页面 http://wiki.fluentnhibernate.org/Database_configuration;有几个启用查询缓存但不启用二级缓存的例子!

2.为每个实体启用缓存

仅启用二级缓存几乎没有任何作用,这就是我被绊倒的地方。二级缓存不仅必须启用,而且为您想要缓存的每个单独的实体类进行配置.

在 XML 中,这是在<class>元素:

<cache usage="read-write"/>

在 Fluent NHibernate(非自动映射)中,它是在ClassMap构造函数或放置其余映射代码的任何位置:

Cache.ReadWrite().Region("Configuration");

必须这样做every将被缓存的实体。作为一种约定,可能可以在一个地方进行设置,但是这样您就几乎错过了使用区域的能力(并且在大多数系统中,您不希望缓存事务数据与配置数据一样多)。

就是这样。这实际上并不难,但要找到一个好的、完整的例子却出人意料地困难,尤其是对于 FNH 来说。


最后一点:这样做的自然结果是当与查询缓存一起使用时,它使得急切连接/获取策略变得非常不可预测。显然,如果 NHibernate 发现查询已被缓存,它就会使没有任何努力首先检查是否all甚至any实际实体的数量被缓存。它几乎只是假设它们是,并尝试单独加载每一个。

这就是SELECT N+1灾难的原因;如果 NH 注意到实体不在二级缓存中并且只是按照所写的那样正常执行查询,并使用 fetch 和 future 等,那么这也没什么大不了的。但它并没有这样做;相反,它尝试加载每个实体及其关系、子关系、子子关系等等,一次一个.

因此,除非您明确启用了缓存,否则使用查询缓存几乎没有意义all中的实体entire图表,即使如此,您也需要非常小心(通过过期、依赖关系等),缓存的查询不会比它们应该检索的实体更持久,否则您最终将导致性能下降更差。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何让 NHibernate 缓存获取的子集合? 的相关文章

随机推荐

  • 获取 firebase 函数实例 id?

    据我了解 firebase 函数在Google 函数执行环境 这意味着函数在单个实例中执行 根据这个文件 https cloud google com functions docs concepts exec 新的函数实例仅在两种情况下启动
  • pymssql(python模块)无法使用临时表

    这不是一个问题 而是一个先发制人的答案 我从这个网站得到了很多帮助并想回馈 当我尝试使用 pymssql 通过 python 运行它时 我正在努力处理大量 SQL 查询 这些查询失败了 但直接通过 MS SQL 运行时却运行良好 例如 就我
  • 使用 Android Volley 发出 HTTPS 请求

    我正在尝试使用以下代码发出 https 请求 RequestQueue queue Volley newRequestQueue getApplicationContext request new Request
  • Laravel Eloquent 在 with() 函数中使用别名

    再会 laravel 中使用 with 函数时是否可以使用别名 举个例子 posts Post where condition gt with user as friend gt get 简短的回答是否定的 但您可以定义与要使用的别名的关系
  • 有聚合物模板的印章活动吗?

    我试图在每次标记其内容时将输入元素聚焦在聚合物模板内 问题是在模板加载之前我无法选择输入元素 目前 我只是使用 setTimeout 在模板加载后 100 毫秒集中输入 但我想知道是否有更优雅的解决方案 此外 自动对焦属性不起作用 因为模板
  • java regex,仅当不在引号或括号中时才以逗号分隔

    我想通过正则表达式进行java split 当字符串不在单引号或括号中时 我想在每个逗号上分割字符串 例子 Hello my friend how are you should give hello my friend how are yo
  • 搜索引擎可以读取 CSS 吗?

    我用标签来表示句子的重要性 然而 它破坏了页面风格的一致性 所以我用CSS把它改回来 结果是 对于访问者来说是相同的 但对于搜索引擎 SE 来说 显然是不同的 这正是SE们所烦恼的 所以我的问题是SE们能否读取CSS 并用它进一步判断整个页
  • 生成具有给定分布的随机数

    看看这个问题 快速选择随机数的概率 https stackoverflow com questions 26092977 swift probability of random number being selected 最上面的答案建议使
  • 如何防止 HTML 文本孤儿?

    我经常在图像周围包裹文字 有时文字包裹起来很笨拙 如下所示 在 HTML 中 图像向左浮动 文本如下 p img src images image p p This is my David Copperfield em I was born
  • 如果覆盖率低于一定百分比,则单元测试失败

    我制作了一个执行的 makefilego test cover 是否有可能失败make unit tests如果覆盖范围低于 X 则命令 我该怎么做呢 您可以使用TestMain在你的测试中做到这一点 TestMain 可以充当测试的自定义
  • 我可以将 JPA 2.0 与 Google App Engine 一起使用吗?

    我可以将 JPA 2 0 例如 EclipseLink 与 Google App Engine 一起使用吗 Google AppEngine 的 DataNucleus 插件支持 JDO 和 JPA API 来访问 Google AppEn
  • 将属性类型作为参数传递

    有没有办法将属性作为参数传递给函数 class Car let doors Int 4 let price Int 1000 有没有办法将 Car 属性作为类型传递给函数 我想实现以下目标 func f1 car Car property
  • 无法将 QMap 传递到 SLOT

    所以 这有效 h public slots void addMenu QString passedName signals void clicked const QString text cpp signalMapper new QSign
  • Spring JPA自定义查询与WHERE条件中的参数组合?

    如何在 Spring Data 中编写至少使用三个参数之一的 JPA 查询 我有这三个参数 Id PK Name Surname 客户端必须至少提供这三个参数之一 我想通过这些非空参数找到用户 是否可以为我的存储库创建此类自定义查询 或者我
  • SWIG 的 Python ctypes 回调函数

    我有一个 SWIG C 函数 它需要一个函数指针 WNDPROC 并且想给它一个由 ctypes WINFUNCTYPE 包装的 Python 函数 在我看来 这应该是兼容的 但 SWIG 的类型检查会引发异常 因为它不知道 ctypes
  • detached 和 allocateCurrentContext 是什么意思?

    当我将作业添加到队列中时 DispatchWorkItemFlags 为我们提供了几个选项可供选择 public func sync
  • 为所有图像添加前缀(递归)

    我有一个包含 5000 多张图像的文件夹 全部带有 JPG 扩展名 我想要做的就是递归地向所有图像添加 thumb 前缀 我发现了一个类似的问题 重命名文件和目录 添加前缀 https stackoverflow com questions
  • 地址栏中的 https 锁和公司名称

    我注意到在查看贝宝的网站时 他们的公司名称位于 Chrome 中的锁定图标旁边 这是因为他们创作了 ssl 证书 还是您认为他们是如何实现这一目标的 这是我一直很好奇的事情 但在搜索过程中我很难找到任何答案 您需要一个称为 扩展验证 EV
  • PowerPoint 命令,例如在 Office javascript API 上插入幻灯片或应用等效主题

    我正在开发一个 PowerPoint 加载项 将来它将在 Office Store 中发布 但它是VSTO项目 C 和winforms 无法发布 根据我的搜索 它一定是 Office Web Add in 项目 清单 xml 和网页 我正在
  • 如何让 NHibernate 缓存获取的子集合?

    我有一个相当简单的条件查询来获取子集合 如下所示 var order Session CreateCriteria