在“卸载”方法中关闭连接

时间:2011-07-11 11:04:42

标签: c# asp.net database-connection connection-pooling page-lifecycle

我继承了一个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”事件,以及为什么会发生这种情况。

5 个答案:

答案 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交互并修改其值。后代类有两种方法可以打破模式:

  1. 直接致电_conn.Close()。如果连接未打开,则不会将其置于EndConnection中。

  2. 通过将_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. } 的值。

  3. 考虑更改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)

没有。以下面的例子为例。

如果用户关闭浏览器会怎样?然后将不会调用卸载功能,您将与数据库建立打开连接。

关于StackOverflow的这个Unload问题与您有类似的问题。