如何使NHibernate的缓存中提取子集合? [英] How do I make NHibernate cache fetched child collections?

查看:161
本文介绍了如何使NHibernate的缓存中提取子集合?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个非常简单的标准查询提取子集合,像这样:

I've got a fairly simple criteria query that fetches child collections, like so:

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教授,我已经验证这使得只有一个往返到数据库(如预期)与冷缓存;然而,在连续执行,它仅检索订单从缓存中,然后点击使用SELECT(N + 1)数据库在图中每一个孩子的实体,如

Using NH Prof, I've verified that this makes just one round trip to the database (as expected) with a cold cache; however, on successive executions, it retrieves only the Order from the cache and then hits the database with a SELECT(N+1) for every child entity in the graph, as in:

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;

等等等等。显然,它不是缓存的全部的查询或图形,只有根实体。第一个缓存查询行实际上有所有的加入条件它应该 - 它肯定缓存的查询本身的正确,只是不实体的,很明显。

And so on and so forth. Clearly it's not caching the whole query or graph, only the root entity. The first "cached query" line actually has all of the join conditions that it's supposed to - it's definitely caching the query itself correctly, just not the entities, apparently.

我已经使用SysCache,SysCache2尝试这样做,甚至哈希表缓存提供商和我似乎总是得到同样的行为(NH版本3.2.0)。

I've tried this using the SysCache, SysCache2, and even HashTable cache providers and I always seem to get this same behaviour (NH version 3.2.0).

谷歌搜索变成了一些古老的问题,如:

Googling turned up a number of ancient issues, such as:

  • NH-195:儿童藏品没有被存储在二级缓存
  • <一个href="https://forum.hibernate.org/viewtopic.php?p=2368642&sid=80db14f4554220de0bcbef3e84b58399">Syscache2第2级缓存:儿童科尔。对象重新查询
  • SysCache和SysCache2之间古怪的差异
  • <一个href="http://ayende.com/blog/4046/nhibernate-beware-of-inadvisably-applied-caching-strategies">NHibernate - 谨防inadvisably应用缓存策略(Ayende - 当然他只困扰谈不上什么的没有的做,而不是如何解决它...)
  • NH-195: Child collections are not being stored in the second level cache
  • Syscache2 2nd level cache: Child coll. objects requeried
  • Weird differences between SysCache and SysCache2
  • NHibernate – Beware of inadvisably applied caching strategies (Ayende - of course he only bothers to mention what not to do, not how to fix it...)

不过,这一切似乎都被固定在很久以前,我也得到了同样的不良行为,无论我使用的人员。

However, these all seem to have been fixed a long time ago, and I get the same bad behaviour regardless of which provider I use.

我通过SysCache和SysCache2 NHForge文档阅读>而且似乎没有任何东西我失踪。我试图加入 cacheRegion 行到的Web.config 文件的查询中涉及的所有表,但它不'T改变任何东西(和AFAIK这些元素只是为了的无效的缓存,所以他们不应该反正无所谓)。

I've read through the NHForge documentation on SysCache and SysCache2 and there doesn't seem to be anything I'm missing. I've tried adding cacheRegion lines to the Web.config file for all tables involved in the query, but it doesn't change anything (and AFAIK those elements are just to invalidate the cache, so they shouldn't matter anyway).

通过所有这些,所有的似乎是固定/解决超历史的问题,我想这没可能的还是的是NHibernate的一个bug,它必须是东西,我做错误。不过什么?

With all of these super-old issues that all seem to be fixed/resolved, I figure this can't possibly still be a bug in NHibernate, it must be something that I'm doing wrong. But what?

有没有我需要的时候取相结合NHibernate的说明与二级缓存做一些特别的东西?我缺少的是在这里吗?

Is there something special I need to do when combining fetch instructions in NHibernate with the second-level cache? What am I missing here?

推荐答案

我还是设法想出解决办法,这样其他人终于可以得到一个明确的答案:

I did manage to figure this out, so other folks can finally get a straight answer:

要概括起来讲,我一直困惑于在二级缓存和查询缓存之间的差别了一会儿;贾森的回答是技术上是正确的,但不知何故没有点击我。这是我会怎样解释:

To sum it up, I've been confused for a while on the difference between the second-level cache and the query cache; Jason's answer is technically correct but it somehow didn't click for me. Here is how I would explain it:

  • 查询缓存保持跟踪的哪些实体的是通过查询发射。它的没有的缓存整个结果集。这是做的相当于 Session.Load 在延迟加载实体;它知道/预期存在,但不跟踪的任意的有关它的其他信息,除非特别要求,此时它会实际加载的真正的实体。

  • The query cache keeps track of which entities are emitted by a query. It does not cache the entire result set. It's the equivalent of doing a Session.Load on a lazy-loaded entity; it knows/expects that one exists but doesn't track any other information about it unless specifically asked, at which point it will actually load the real entity.

二级缓存跟踪实际的数据的每个实体。当NHibernate的需要加载的任何实体,其ID(凭借 Session.Load Session.Get ,懒惰-loaded关系,或在上面的例子中,一个实体的参考这是一个高速缓存查询的一部分),它看起来在二级缓存第一。

The second-level cache tracks the actual data for each entity. When NHibernate needs to load any entity by its ID (by virtue of a Session.Load, Session.Get, lazy-loaded relationship, or, in the case above, an entity "reference" that's part of a cached query), it will look in the second-level cache first.

当然,这是非常合情合理的后见之明,但是当你听到的术语查询缓存和二级缓存被用于几乎互换在很多地方它不是那么明显了。

Of course this makes perfect sense in hindsight, but it's not so obvious when you hear the terms "query cache" and "second-level cache" being used almost interchangeably in so many places.

基本上有两个组,每组两个设置,你需要为了看到查询缓存预期的结果进行配置:

Essentially there are two sets of two settings each that you need to configure in order to see the expected results with query caching:

在XML配置,这意味着将以下两行:

In XML configuration, this means adding the following two lines:

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

在功能NHibernate,它是这样的:

In Fluent NHibernate, it's this:

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

请注意, UseSecondLevelCache 以上,因为(在此张贴的时间)是永远上的Fluent NHibernate的维基页面;有使查询缓存,但没有二级缓存的几个例子!

Please note the UseSecondLevelCache above because (at the time of this posting) it is never mentioned on the Fluent NHibernate wiki page; there are several examples of enabling the query cache but not the second-level cache!

刚刚启用二级缓存确实pretty的多少无关,而这正是我被绊倒。第二级缓存,必须不仅启用,但配置要缓存的每一个人实体类的。

Just enabling the second-level cache does pretty much nothing, and this is where I got tripped up. The second-level cache has to be not only enabled but configured for every single individual entity class that you want cached.

在XML,这里面做了&LT;类&GT; 元素:

In XML, this is done inside the <class> element:

<cache usage="read-write"/>

在功能NHibernate(非自动映射),它的完成了 ClassMap 构造函数或任何你把你的映射code休息:

In Fluent NHibernate (non-automap), it's done in the ClassMap constructor or wherever you put the rest of your mapping code:

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

这必须为的实体将被缓存完成。这也可能是可以建立在一个地方作为一个惯例,但你pretty的太多错过了使用区域(在大多数系统中,您不想缓存交易数据多达配置数据)的能力。

This has to be done for every entity that is going to be cached. It's probably possible to set up in one place as a convention, but then you pretty much miss out on the ability to use regions (and in most systems you don't want to cache transactional data as much as configuration data).

就是这样。这真的不是很难做,但令人惊讶的很难找到一个很好的,完整的例子,尤其是对FNH。

And that's it. It's really not that hard to do but surprisingly difficult to find a good, complete example, especially for FNH.

还有最后一点:这样做的必然结果是,这让渴望加盟/抓取策略非常联合国predictable与查询缓存使用时显然,如果NHibernate的看到一个查询缓存,它将使的没有任何力气的先检查一下,如果的所有的,甚至实际实体的任意的被缓存。它pretty的简单,只是假定他们,并试图单独加载每一个了。

One last point: The natural consequence of this is that it makes eager join/fetching strategies very unpredictable when used with the query cache. Apparently, if NHibernate sees that a query is cached, it will make no effort whatsoever to check first if all or even any of the actual entities are cached. It pretty much just assumes that they are, and tries to load each one up individually.

这是对SELECT N + 1灾害的原因;它不会是什么大不了的事,如果NH注意到,实体没有在二级缓存,只是执行的查询通常,书面,有取和期货等。不过,这并不这样做;相反,它尝试加载每一个实体,它的关系,及其子关系,及其分子关系,等等,的一次一个

This is the reason for the SELECT N+1 disaster; it wouldn't be that big of a deal if NH noticed that the entities weren't in the second-level cache and just executed the query normally, as written, with fetches and futures and so on. But it doesn't do that; instead it tries to load every entity, and its relations, and its sub-relations, and its sub-sub-relations, and so on, one at a time.

因此​​在使用查询缓存,除非你明确启用缓存几乎是没有意义的所有的实体在全部的图形,甚至那时,你马上要非常小心(按到期,相关性等方式),其缓存的查询不垮,他们应该获取的实体,否则你最终只会使性能更差。

So there is almost no point in using the query cache unless you've explicitly enabled caching for all of the entities in the entire graph, and even then, you'll want to be very careful (by way of expirations, dependencies, etc.) that cached queries don't outlast the entities that they are supposed to retrieve, otherwise you will just end up making the performance worse.

这篇关于如何使NHibernate的缓存中提取子集合?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆