【发布时间】:2018-09-26 18:51:13
【问题描述】:
我有一个带有 C# 后端的 ASP.Net 应用程序,它使用 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,请求之间没有共享会话,会话正在正确处理。
问题是,当我开始浏览 Web 的不同部分(因此执行新请求)时,进程开始像图像中一样增长......并且在某个时刻,网页响应运行时错误或超时。
如何控制这种行为? 每个请求只能有一个进程,并且在处理时关闭进程?
编辑 2:
我错了,会话管理是用第一个答案中提供的方法正确完成的。有进程,但它们由 NHibernate 正确管理。
【问题讨论】:
-
无论代码的其余部分做什么,你有一个 static
DisposeSession的事实就是 gets 一个会话只是为了 不安全地处置这意味着您的数据访问代码存在严重问题。 session 与连接相同 - 您在using()块中尽可能短地使用它,因此无论如何它都会被释放和关闭。你不分享它。如果发生异常,会话无论如何都是无用的,必须丢弃。你分享的是工厂。 -
换句话说,无法提供这些信息。您的代码正在泄漏连接,保证在出现异常时会泄漏会话,如果多个请求尝试使用同一个会话,则保证会阻止。问题不在于
DisposeSession。你甚至不应该有这样的方法 -
@PanagiotisKanavos,你不知道
CurrentSessionContext是做什么的。对我来说,它看起来很可能确实从HttpContext之类的东西中检索会话,这是 Web 应用程序中的一种常见做法,并允许在短时间内处理它们(http 请求应该很短),而无需在请求之间共享,并且如果正确处理请求结束,则不会泄漏。 -
这一点都不难。不比通过控制器或网络表单正确处理会话保持更难。对于 MVC,我个人更喜欢使用
ActionFilter来处理这个问题,这比在控制器中全局处理它提供更多的控制权。 http 请求通常很适合工作单元,因此将会话绑定到它非常有意义。如果http请求太长导致死锁问题,那么他们所做的业务可能有问题。但是许多其他模式也是有效的,只要它们使会话保持短暂且不共享。 -
关于提前打开连接:是的,但问题不大。在查询发生之前不会发出锁,并且不会在读取时发出锁,除非使用诸如发出共享锁的 SQL Server 旧式读取提交模式之类的东西。 (幸运的是,SQL Server 现在支持其“已提交读快照”模式,它的工作方式有点像 Oracle 多年以来的已提交读操作,没有锁。)对于具有更强隔离模式的事务,当然它们不应该跨越 ORM UoW 之类的东西,这通常此类交易涉及到很多对象。
标签: c# asp.net sql-server nhibernate