我继承了一个Web框架,以前的开发人员在页面生命周期的init / unload方法中打开并关闭了他的数据库连接。基本上构造函数是这样的(简化以证明这一点);
public class BasePage
{
protected DBConnection _conn;
public BasePage()
{
Init += StartConnection;
Unload += EndConnection;
}
private void StartConnection(object sender, EventArgs e)
{
_conn = new DBConnection(Application["connectionstring"].ToString());
}
private void EndConnection(object sender, EventArgs e)
{
if (_conn == null)
return;
if (_conn.Connection.State == ConnectionState.Open)
{
_conn.Close();
_conn.Dispose();
}
}
}
自从我来到这里以来,发展一直很快,所以我从未停下来考虑它。最近,访问已经开始,我们已经开始获得可怕的“Timeout过期。在从池中获取连接之前已经过了超时时间......”错误。
我目前正在查看其余的代码,寻找可能的连接泄漏,但上面的代码从来没有完全适合我,我想消除它作为潜在的罪魁祸首。关于那个问题;
即使在发生异常的情况下,我是否可以依赖“卸载”方法?或者任何人都可以使用上述模式看到任何其他潜在的问题,这会使它成为这些连接泄漏的主要嫌疑人?
干杯,
米奇
编辑:在调试中,即使存在异常,也始终会调用unload方法。我真的只需要知道不会调用此方法的任何情况,所以我可以弄清楚这是否需要首先进行重构。
编辑:感谢那些到目前为止做出回应的人,但请不要再提出有关IDisposable课程,或“使用”或“捕获/最终”模式的建议 - 这不是我的问题!我的问题是具体的是一个页面是否可以运行其“Init”事件但是无法运行是“Unload”事件,以及为什么会发生这种情况。答案 0 :(得分:2)
我总是使用下面的块soemthing
using( SqlConnection)
{
}
这样它就不会出现任何问题
如果您不想再次编写打开连接的代码,请再次创建一个类
public class SqlConnectionManager
{
public SqlConnection GetSqlConnectionManager()
{
//create and return connection
//SqlConnection con = new SqlConnection();
//return con;
}
}
在您的班级文件中
SqlConnection conn = null;
using (conn = (new SqlConnectionManager()).GetSqlConnectionManager())
{
//do work with connection
}
因此,通过上述方式,您不需要反复编写代码,也无需编写代码来关闭连接,因为它会通过使用块自动进行处理。
答案 1 :(得分:2)
我没有关于这是否安全的确切知识,但我查看了System.Web.UI.Page类的源代码,并且私有ProcessRequestCleanup()触发了unload事件,除非请求是异步的或者是跨页请求。对清理方法的调用是在finally块中,该块耦合到围绕ProcessRequest的try块。进程请求正在触发从PreInit到Render的所有页面生命周期事件。这意味着即使发生异常,也会始终触发卸载(异步和跨页情况除外)。
但是,由于卸载的行为并未完全记录,因此在我的页面中使用此代码会感到非常不安。
答案 2 :(得分:1)
编辑:根据PHeiberg的回答,这绝对可以在.net 4中进行,并且可以假设将始终调用卸载。
我也检查了.net 2.0代码,同样也是如此。
答案 3 :(得分:1)
(非常)快速测试(VS2010 Web服务器,.net v4)向我展示了在引发未处理的异常时(至少在Page_Load中引发)时调用Unload事件 ,所以原则看起来应该有效。
如果连接打开,示例中列出的模式仅为dispose
连接。
当_conn
受到保护时,来自BasePage的页面可以与_conn交互并修改其值。后代类有两种方法可以打破模式:
直接致电_conn.Close()
。如果连接未打开,则不会将其置于EndConnection中。
通过将_conn
设置为null或为其分配新的DBConnection实例来修改private void EndConnection(object sender, EventArgs e)
{
if (_conn == null)
{
return;
}
if (_conn.Connection.State == ConnectionState.Open)
{
_conn.Close();
}
_conn.Dispose(); // always dispose even if not actually open. It may have been closed explicitly elsewhere.
}
的值。
考虑更改EndConnection方法,以便_conn 始终处理。
_conn
EndConnection无法捕获案例2。考虑将private DBConnection _conn;
protected DBConnection Connection {
get
{
return _conn;
}
}
设为私有并提供getter属性:
{{1}}
阻止后代类更改_conn的值。
最后,DBConnection是你自己的一类吗?我只问你引用“_conn.Connection.State”而不仅仅是_conn.State。如果是这样,只需仔细检查DBConnection的Dispose方法是否正确配置其Connection实例。
答案 4 :(得分:0)