关闭“卸载”中的连接方法
我继承了一个 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();
}
}
}
自从我来到这里以来,发展速度相当快,所以我从未停下来考虑它。最近,访问量有所增加,我们开始收到可怕的“超时已过期。从池中获取连接之前超时时间已过...”错误。
我目前正在检查其余的代码,寻找可能的连接泄漏,但上面的代码从来没有完全适合我,我想消除它作为潜在的罪魁祸首。那么接下来的问题;
即使发生异常,我是否可以始终调用“卸载”方法?或者任何人都可以使用上述模式看到任何其他潜在问题,从而使其成为这些连接泄漏的主要嫌疑人?
干杯,
Mikey
编辑:在调试中,即使出现异常,卸载方法也总是被调用。我真的只需要知道不会调用此方法的任何场景,这样我就可以弄清楚这是否是我需要首先重构的部分。
编辑:感谢那些迄今为止做出回应的人,但请不要再提出有关 IDisposable 类或“使用”或“catch/finally”模式的建议 - 这不是我的问题!我的问题具体是,页面是否可以运行其“Init”事件,但随后无法运行“Unload”事件,以及为什么会发生这种情况。
I have inherited a web framework whereby the previous developer has opened and closed his database connections in the init/unload methods of the page life cycle. Essentially constructor is like this (simplified to demonstrate the point);
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();
}
}
}
Development has been pretty fast since i got here so I never stopped to consider it. Recently, visits have been up and we've started getting the dreaded "Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool..." error.
I'm currently going through the rest of the code looking for possible connection leaks, but the above code has never quite sat right with me and I want to eliminate it as a potential culprit. On to the question then;
Can i rely on the "unload" method ALWAYS being called, even in the event of an exception? Or can anyone see any other potential issues using the above pattern that would make it a prime suspect for these connection leaks?
Cheers,
Mikey
EDIT: In debugging, the unload method always gets called even if there is an exception. I really just need to know of any scenarios where this method would not be called so i can figure out if this is the bit i need to be refactoring first.
EDIT: Thanks to those who have responded so far but please no more recommendations about the IDisposable class, or the "using" or "catch/finally" patterns - This wasn't what my question was! My question is specifically whether a page could ever run its "Init" event but then fail to run is "Unload" event, and why this might happen.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我不知道这是否安全,但我浏览了 System.Web.UI.Page 类的源代码,卸载事件由私有 ProcessRequestCleanup() 触发,除非请求是异步的或跨页面请求。对 clean up 方法的调用位于与 ProcessRequest 周围的 try 块耦合的 finally 块内。处理请求正在触发从PreInit到Render的所有页面生命周期事件。这意味着即使发生异常,卸载也将始终被触发(异步和跨页情况除外)。
然而,在我的页面中包含此代码我会感到非常不安,因为卸载的行为没有准确记录。
I have no definitive knowledge about if this is safe, but I poked through the Source code for the System.Web.UI.Page class and the unload event is triggered by the private ProcessRequestCleanup() unless the request is asyncronous or a cross page request. The call to the clean up method is inside a finally block coupled to a try block that's surrounding the ProcessRequest. Process request is triggering all the page life cycle events from PreInit to Render. That would mean that Unload will always be triggered (except for in the async and cross page cases), even if an exception occur.
However I would feel very uneasy having this code in my pages since the behaviour of unload isn't exactly documented.
我总是使用如下的 using block ,
创建一个类,那么它永远不会引起任何问题
这样如果您不想编写用于打开连接的代码并再次
在您的类文件中
所以通过上述方式您不需要再次编写代码再次,也不需要编写代码来关闭连接,因为它会通过 using 块自动释放。
I always make use of using block soemthing as below
so that it never cause any problem
if you dont want to write code for opening connection again and again create one class
In You class files
So by the above way you do not need to write code again and again and there is also no need to write code to close connection because its automatically get dispose by using block.
一个(非常)快速的测试(VS2010 Web 服务器,.net v4)向我表明,当引发未处理的异常时(至少在 Page_Load 中引发),会调用 Unload 事件,因此原理看起来就像它应该起作用一样。
示例中列出的模式仅在连接打开时
dispose
'ing 连接。由于
_conn
受到保护,BasePage 的后代页面可以与 _conn 交互并修改其值。后代类有两种方法可以打破这种模式:直接调用
_conn.Close()
。如果连接未打开,则不会在 EndConnection 中将其释放。通过将
_conn
设置为 null 或为其分配 DBConnection 的新实例来修改它的值。考虑更改 EndConnection 方法,以便始终处置 _conn。
情况 2 无法被 EndConnection 捕获。考虑将 _conn 设为私有并提供 getter 属性:
这可以防止后代类更改 _conn 的值。
最后,DBConnection 是您自己的类吗?我只是在您引用“_conn.Connection.State”时才问,而不仅仅是_conn.State。如果是这样,只需仔细检查 DBConnection 的 Dispose 方法是否正确处置其 Connection 实例。
A (very) quick test (VS2010 web server, .net v4) has shown me that the Unload event is called when an unhandled exception is raised (at least if raised in Page_Load), so the principle looks like it should work.
The pattern as listed in the example is only
dispose
'ing the connection if the connection was open.As
_conn
is protected, pages descended from BasePage can interact with _conn and modify its value. There are two ways for descendant classes to break the pattern:Call
_conn.Close()
directly. If the connection is not open, it is not disposed in EndConnection.Modify the value of
_conn
by either setting it to null or assigning a new instance of DBConnection to it.Consider changing your EndConnection method, so that _conn is always disposed.
Case 2 can't be caught by EndConnection. Consider making
_conn
private and providing a getter property:which prevents descendant classes from changing the value of _conn.
Lastly, is DBConnection a class of your own? I only ask as you quote "_conn.Connection.State" rather than just _conn.State. If so, just double check that the Dispose method of DBConnection disposes its Connection instance correctly.
编辑:根据 PHeiberg 的回答,这在 .net 4 中绝对是可能的,并且可以假设卸载将始终被调用。
我也检查了.net 2.0代码,那里也是如此。
EDIT: As per PHeiberg's answer this is definitely possible in .net 4 and one can assume unload will always be called.
I checked the .net 2.0 code as well and the same is also true there.
不,看下面的例子。
如果用户关闭浏览器会发生什么?然后,将不会调用 Unload 函数,并且您将拥有与数据库的打开连接。
这Unload 问题也有与您类似的问题。
No. Take the following example.
What happens if the user closes the browser? The Unload function will then not be called and you will have an open connection to the database.
This Unload question on StackOverflow has a similar problem that you are having.