我正在使用具有 Fluent NHibernate 的二级缓存提供程序 SysCache2,使用标准的 fluent 配置(启用查询缓存,这似乎是一般建议),并以通常的方式定义了基于表的依赖项。
流利:
config.Cache(c => c
.ProviderClass<NHibernate.Caches.SysCache2.SysCacheProvider>()
.UseQueryCache()
.UseSecondLevelCache()
.UseMinimalPuts()
)
网络配置:
<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 按 ID 缓存的方式所预期的那样。后续请求不会命中数据库,而使数据库中的记录失效会导致Entity失效,从而导致在下一次请求期间进行后续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 - 如何使 NHibernate 缓存获取子集合?请参阅“多一点”部分
Ayende Caching Strategies他提到确保最后“实体也被缓存”
目前我可以避免这种情况的唯一方法是在每次请求后清除查询缓存——这几乎使它无用。当某个实体无效时,我需要查询缓存来清除该实体的所有内容——而不仅仅是单个记录。
有任何想法吗?