我在Fluent NHibernate中使用二级缓存提供程序SysCache2,使用标准fluent配置(按照一般建议启用了查询缓存),并以通常的方式定义了基于表的依赖关系。
流利:
config.Cache(c => c
.ProviderClass<NHibernate.Caches.SysCache2.SysCacheProvider>()
.UseQueryCache()
.UseSecondLevelCache()
.UseMinimalPuts())
Web.Config:
<cacheRegion name="User" relativeExpiration="7200">
<dependencies>
<tables>
<add name="User" databaseEntryName="OldClient" tableName="tbl_users" />
</tables>
</dependencies>
用户映射:
public class UserMap : ClassMap<User>
{
public UserMap()
{
Table("Users");
....
// caching
Cache.IncludeAll().ReadWrite().Region("Users");
}
}对于单个请求,一切都按预期运行,即:
Session<User>.Get()正如从NHibernate caches by ID的方式所期望的那样。后续请求不会命中数据库,而使数据库中的记录无效会导致实体无效,从而导致在下一次请求期间调用后续SQL。一切都好。
问题出在查询缓存上。首先,一切都运行得很好。执行调用,例如:
Session<User>.Query(item => item.Active == true) 如您所料,结果是SQL调用(SELECT * FROM Users WHERE Active = true)。并且随后的执行不会产生SQL。太棒了。直到查询集中的单个记录在数据库中被改变时为止。执行相同的查询,然后生成一个SELECT N+1:
SELECT * FROM Users WHERE ID = 1
SELECT * FROM Users WHERE ID = 2
SELECT * FROM Users WHERE ID = 3
SELECT * FROM Users WHERE ID = 4
...我在其他地方找到了对此的引用,尽管没有解决方案:
StackOverflow - How do I make NHibernate cache fetched child collections?请参阅“更多一点”部分
Ayende Caching Strategies他在结尾提到要确保实体也被缓存
目前我可以避免这种情况的唯一方法是在每次请求后清除查询缓存-这几乎使它变得无用。当特定实体失效时,我需要让查询缓存清除该实体的所有内容-而不仅仅是单个记录。
有什么想法吗?
发布于 2013-02-07 18:21:41
根据您发布的两个链接,查询缓存将缓存查询结果的in,并开始逐个获取实体:如果缓存中有这些in,那么很好,如果没有,那么您现在有很多selects。
在这一点上,我假设您选择的实体不在二级缓存中(还在吗?)。我从来没有使用过基于表的依赖关系,我们使用的是command based dependencies,我只是测试了一下,如果一个实体被标记为无效,那么只有这个缓存的实体,而不是整个缓存区域,会被抛出缓存。
检查配置以确保它是正确的,也许当你认为你正在命中二级缓存时,你实际上正在命中会话缓存?请确保您正在测试缓存是否跨不同的会话工作。
在任何情况下,我建议您查看NHibernate的调试级日志,看看二级缓存实际发生了什么,在那里您将能够看到所有缓存命中/未命中。我可以给您的另一个技巧是在您的配置中启用generate_statistics标志。流利:
config.ExposeConfiguration(c => c.SetProperty("generate_statistics", "true"));之后,您可以访问会话工厂中感兴趣的数据,如Session.SessionFactory.Statistics.SecondLevelCacheMissCount和Session.SessionFactory.Statistics.SecondLevelCacheHitCount。结合使用这两种方法,您应该能够找出问题的原因。
https://stackoverflow.com/questions/14193392
复制相似问题