NHibernate超时与SQL Server
我有一个ASP.Net应用程序与后端在C#中使用NHibernate与SQL Server。NHibernate超时与SQL Server
最近我注意到,在很长的时间做一些任务在网络中的某一页,它冻结和超时进来(NHibernate的除外)。
超时问题后,我去SQL Server Management Studio中,我可以在显示屏上看到有像几十过程没有任何状态,所有到同一个数据库:
我有在任何地方搜索解决方案,我不知道我是否可能错误地处理会话。下面是我如何处置会话:
public static void DisposeSession()
{
FlushSession(true); // Method that does a commit if there is a transaction
ISession Session = CurrentSessionContext.Unbind(sessionFactory);
if (Session != null)
{
Session.Close();
Session.Dispose();
}
}
编辑1:
我目前使用WebForms和有请求之间没有共享会话,会话被正确配置。
问题是,当我开始去虽然我的网络的不同部分(这样新的请求),该过程将开始,像图像中成长......在某一点,该网页与运行时错误或超时响应。
我该如何控制这种行为? 每个请求只有一个进程,处理时可以关闭进程?
编辑2:
我错了,会话管理是正确的,在第一个答案提供的方法进行。有一些进程,但它们由NHibernate正确管理。
首先,确保你的请求之间CurrentSessionContext
不共享会话。
通常这种情况下在HttpContext.Current.Items
字典存储会话。这是确保它不会与其他http请求共享的安全场所。
如果它在请求之间共享会话,那么一旦加载,大多数用户的应用程序就会失败。
如果它使用ThreadContext
或CallContext
,由于“ASP.Net线程敏捷性”导致某些http请求切换线程并丢失以前的ThreadContext
和CallContext
,它将定期对某些负载下的请求失败。当一个http请求切换线程时,HttpContext.Current.Items
保证被保留,而不是其他的。
如果CurrentSessionContext
看起来正确的,那么解决您的DisposeSession
。它不能确保您的会话将在冲洗失败时关闭。
这也许应该是更喜欢:
public static void DisposeSession()
{
try
{
FlushSession(true); // Method that does a commit if there is a transaction
}
finally
{
ISession Session = CurrentSessionContext.Unbind(sessionFactory);
if (Session != null)
{
// Dispose closes the session too. And Close dispose the transaction
// if there was one. And transaction Dispose rollbacks if it was pending.
Session.Dispose();
}
}
}
然后,检查该DisposeSession
总是叫什么方式你的请求结束。特别是检查触发异常的请求发生了什么。这包括一些与ThreadAbortException
一起工作的重定向案例,如Response.Redirect("...")
。
会话管理:
关于我平时使用的会话管理模式,我绑定了依赖注入,与每个请求的生命周期和HTTP模块,确保它被设置在请求好歹事务由一个动作过滤器(MVC)处理。
你的模式远不止于此。如果你想改变它,你可能会更容易遵循这个blog post series从NHibernate的老计时器贡献者和NHibernate profiler的作者。
你写的是Entity Framework,但不支持* NHibernate。与EF环境不同,会话是一个热门的土豆,必须小心处理。异常和线程安全是主要问题 - 单个数据库错误,您必须创建* new *会话。旧的是无用的。这意味着你不能注入会话,你必须注入工厂。 –
无论我处理EF还是NH,在会话或上下文失败时,我都会放弃它(处置)。只是让它处于这种状态,因为我让异常流动并且我的错误页面不需要会话。当我在一个特定的情况下需要在失败之后进行一些数据库交互并且在同一请求中时,具有该需求的类将持有对会话工厂的依赖关系,并获得仅用于该特定需求的新会话并在随后立即处理。 (BtW,我很可能永远也不会信任失败的EF上下文)。 –
EF上下文不会失败。他们*是*异常安全的。如果你想恢复,例如从死锁,你可以。尽管如此,如果您无法访问*工厂,您必须重新启动请求。 *工厂*相当于DbContext,而不是会话 –
无论代码的其他部分如何,您都有一个* static *'DisposeSession'从*处取得会话*仅仅处理* unsafely *处理它意味着您的数据访问代码存在严重问题。一个* session *和一个连接相同 - 你可以在一个'using()'块中尽可能短的时间使用它,所以无论如何它都会被处理和关闭。你*不*分享它。如果发生异常,则会话无用,必须丢弃。你分享的是*工厂*。 –
换句话说,这是不可能的帮助这些信息。你的代码泄漏了连接,如果发生异常,它肯定会泄漏会话,如果有多个请求尝试使用同一个会话,它会*保证*阻止。但问题不是'DisposeSession'。你甚至不应该有这样的方法 –
@PanagiotisKanavos你是对的......可以在“Application_BeginRequest”方法中创建和保存会话,并将其置于“Application_EndRequest”中,而不使用静态方法,也不需要使用...是它可能和安全? – rpfc