C# 优化nhibernate会话工厂,webApp启动时间非常慢
我已经实现了测试应用程序。它使用fluent nhibernate映射到mssql db中的db对象。因为我想学习微调nhib。mvc3应用程序,我正在使用此应用程序。用于只有一个简单实体(具有10个枚举属性和一个字符串属性)的测试目的。 所以,这确实是光波,但根据nhibernate profiler,启动时间是4.37秒。这对于渲染一个实体(只有几行已选中/未选中的属性)来说非常缓慢 代码如下。 Domain.SessionProvider.csC# 优化nhibernate会话工厂,webApp启动时间非常慢,c#,asp.net-mvc-3,nhibernate,fluent-nhibernate,C#,Asp.net Mvc 3,Nhibernate,Fluent Nhibernate,我已经实现了测试应用程序。它使用fluent nhibernate映射到mssql db中的db对象。因为我想学习微调nhib。mvc3应用程序,我正在使用此应用程序。用于只有一个简单实体(具有10个枚举属性和一个字符串属性)的测试目的。 所以,这确实是光波,但根据nhibernate profiler,启动时间是4.37秒。这对于渲染一个实体(只有几行已选中/未选中的属性)来说非常缓慢 代码如下。 Domain.SessionProvider.cs public static ISession
public static ISessionFactory CreateSessionFactory()
{
var config = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008
.ConnectionString(c => c.FromConnectionStringWithKey("myConnection")))
.Mappings(m => m.FluentMappings.Add<FeaturesMap>())
.ExposeConfiguration(p => p.SetProperty("current_session_context_class", "web"))
.BuildConfiguration();
return config.BuildSessionFactory();
}
在myController中,我有以下内容:
public ActionResult Index()
{
return View(GetData());
}
private IList<FeaturesViewModel> GetData()
{
List<Features> data;
using (ISession session = MvcApplication.SessionFactory.GetCurrentSession())
{
using (ITransaction tx = session.BeginTransaction())
{
data = session.Query<Features>().Take(5).ToList();
tx.Commit();
var viewModelData = FeaturesViewModel.FromDomainModel(data);
return viewModelData;
}
}
}
public ActionResult Index()
{
返回视图(GetData());
}
私有IList GetData()
{
列出数据;
使用(ISession session=MVCAPApplication.SessionFactory.GetCurrentSession())
{
使用(ITransaction tx=session.BeginTransaction())
{
data=session.Query().Take(5.ToList();
tx.Commit();
var viewModelData=FeaturesViewModel.FromDomainModel(数据);
返回viewModelData;
}
}
}
正确地说,在HttpApplication(或其子类,如mvcapapplication)的构造函数中创建对象不是一个好主意。最好在应用程序启动处理程序中创建会话工厂
您应该删除NHibernate探查器(因为所有探查器都可能影响测量)。相反,调用CreateSessionFactory()并使用Stopwatch类将其包围起来,以获得准确的测量结果
您的数据库服务器响应慢吗?由于连接池,这可能只有在第一次出现时才明显
NHibernate确实需要一些时间来初始化,但是使用一个轻量级实体4秒钟似乎太多了。当然,这会受到测试系统总体性能的影响。您可以通过缓存配置来缩短启动时间(web和windows应用程序)。以下课程将完成此工作:
using System.IO;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Web;
using NHibernate.Cfg;
namespace NH32AutoMap.Core
{
public class ConfigurationFileCache
{
private readonly string _cacheFile;
private readonly Assembly _definitionsAssembly;
public ConfigurationFileCache(Assembly definitionsAssembly)
{
_definitionsAssembly = definitionsAssembly;
_cacheFile = "nh.cfg";
if (HttpContext.Current != null) //for the web apps
_cacheFile = HttpContext.Current.Server.MapPath(
string.Format("~/App_Data/{0}", _cacheFile)
);
}
public void DeleteCacheFile()
{
if (File.Exists(_cacheFile))
File.Delete(_cacheFile);
}
public bool IsConfigurationFileValid
{
get
{
if (!File.Exists(_cacheFile))
return false;
var configInfo = new FileInfo(_cacheFile);
var asmInfo = new FileInfo(_definitionsAssembly.Location);
if (configInfo.Length < 5 * 1024)
return false;
return configInfo.LastWriteTime >= asmInfo.LastWriteTime;
}
}
public void SaveConfigurationToFile(Configuration configuration)
{
using (var file = File.Open(_cacheFile, FileMode.Create))
{
var bf = new BinaryFormatter();
bf.Serialize(file, configuration);
}
}
public Configuration LoadConfigurationFromFile()
{
if (!IsConfigurationFileValid)
return null;
using (var file = File.Open(_cacheFile, FileMode.Open, FileAccess.Read))
{
var bf = new BinaryFormatter();
return bf.Deserialize(file) as Configuration;
}
}
}
}
然后,在调用BuildSessionFactory之前,我们可以从缓存中读取配置文件,或者如果映射已更改,则构建它并再次缓存它:
public ISessionFactory SetUpSessionFactory()
{
var config = readConfigFromCacheFileOrBuildIt();
var sessionFactory = config.BuildSessionFactory();
在这里您可以找到完整的示例:()。
+如果要使其正常工作,请将域类和映射定义程序集与主应用程序的程序集分离(因为如果映射定义程序集比缓存文件的LastWriteTime新,ConfigurationFileCache类将删除缓存文件)。启动时间真的那么重要吗?在适当的部署中,这种成本不应该经常发生。关于web应用程序。我认为使用光波实体的这个启动时间是“有意义的”。你是说我检查部署吗?我的意思是,如果在部署的环境中每天或每几天发生一次(每当你的应用程序池被回收),代价就不是一个DealBurror。YEP,但是你必须认为这是一个真正的光波实体。因此,它将随着更多实体在我的会话工厂中映射而逐渐增长。想象50个实体具有更复杂的逻辑和关系。所以我确实需要分析一下。任何建议。我做了一些与此示例非常类似的事情…基本上是一个actionfilter,它处理事务和会话处理,并在我的基本控制器上设置ISession属性。考虑到上面的代码,我可以请您向我展示应用程序启动方法的外观。感谢您的原始代码,只需将对CreateSessionFactory()的调用移动到应用程序_Start(),并将对OpenSession()的调用移动到应用程序_BeginRequest()。在应用程序_EndRequest()中添加适当的代码以关闭会话。使用Begin | EndRequest对应于每个请求的会话模式。仅供参考:我已经在3.3上尝试过了,它没有任何区别。也许我的ssd比旧硬盘快,但启动问题仍然存在。
private Configuration readConfigFromCacheFileOrBuildIt()
{
Configuration nhConfigurationCache;
var nhCfgCache = new ConfigurationFileCache(MappingsAssembly);
var cachedCfg = nhCfgCache.LoadConfigurationFromFile();
if (cachedCfg == null)
{
nhConfigurationCache = buildConfiguration();
nhCfgCache.SaveConfigurationToFile(nhConfigurationCache);
}
else
{
nhConfigurationCache = cachedCfg;
}
return nhConfigurationCache;
}
public ISessionFactory SetUpSessionFactory()
{
var config = readConfigFromCacheFileOrBuildIt();
var sessionFactory = config.BuildSessionFactory();