我有一个使用nhibernate和SQL服务器的asp.net-mvc站点,有一些页面非常慢,因为它们需要查看需要查询加入大约25个不同的表。如果我没有进行大型加入需要一段时间,如果我进行多次查询,它似乎还需要一段时间
它是一个非常准备好的重(轻写)数据库,所以我想看看是否有一个很好的方法基本上将我的数据库的整个对象图(我的服务器有足够的内存)加载到二级缓存所以我是确信它很少会击中数据库。我正在使用
NHibernate.Caches.SysCache.SysCacheProvider
作为二级缓存(不是分布式缓存)。这个想法有什么缺陷吗?有推荐的方法吗?
答案 0 :(得分:2)
您正在缓存查询结果,但不是您的实体(这些是单独的缓存) 缓存查询的结果只存储ID;如果你也没有缓存你的实体,则会发出一个查询来加载每个返回的实体(这通常很糟糕) MyDTO类的默认表名是MyDTO,因此它在哪里查找 这看起来像是一个ID查询,你不应该使用一个松散的命名查询,而是一个合适的加载器。(see 17.4. Custom SQL for loading) 一旦设置了加载器和实体缓存,您就可以只使用session.Get(id)检索对象,它将使用二级缓存,只要您在事务内完成所有工作,这是推荐的做法。
答案 1 :(得分:1)
二级缓存始终与Session Factory对象关联。在运行事务时,它在两者之间加载会话工厂级别的对象,以便这些对象可供整个应用程序使用,而不是绑定到单个用户。由于对象已经加载到缓存中,因此每当查询返回一个对象时,就不需要进行数据库事务。
不仅要启用二级缓存,还要为要缓存的每个单独的实体类进行配置。因此,启用缓存映射到15个表的所有15个对象。
在XML中,这是在元素内完成的:
<cache usage="read-write"/>
在Fluent NHibernate(非自动化)中,它在ClassMap构造函数中完成,或者在您放置其余映射代码的任何地方完成:
Cache.ReadWrite().Region("Configuration");
从这里开始,它取决于数据库的大小和负载,以及新数据的存在方式。
如果Db相对较小且写入很少 您可以在每次写入/更新时更新缓存。
ISession.Clear();
ReloadCache();
如果Db很大: 你每天更新一次数据库就可以说是早上12点,然后保持新的&#39;缓存中的数据一天,你也可以。在重新加载时,您将为少数用户获得延迟峰值。
以下是一个例子: http://www.codeproject.com/Articles/529016/NHibernate-Second-Level-Caching-Implementation
如果您的数据库庞大且用户必须获取更新数据,您将手动更新缓存中的数据。
Database db = new Database ();
Transaction tx = db.BeginTransaction ();
try
{
// Read from the cache
MyEntity1 entity1 = cache.Get <MyEntity1> ("pk of entity1");
// Cache is not read from the database
if (entity1 == null) entity1 = db.Get <MyEntity1> ("pk of entity1");
// Entity1 processing
updated = db.Update, (entity1); / / entity1 update saved to the database
if (updated) cache.Put (entity1); / / database update successfully, the update cache
// Transaction processing
tx.commit ();
}
catch
{
tx.Rollback ();
throw;
}