池中的连接耗尽

时间:2012-01-12 20:52:50

标签: c# sql-server ado.net connection-pooling webforms

我有一个Web表单应用程序,它将在GridView中显示记录列表,通过选中多个复选框,您可以批量删除记录。代码本身很简单:

protected void btnDelete_Click(object sender, EventArgs e)
{
    int i = 0;
    try
    {
        foreach (GridViewRow row in GridView1.Rows)
        {
            CheckBox cb = (CheckBox)row.FindControl("ID");
            if (cb != null && cb.Checked)
            {
                int profileID = Convert.ToInt32(GridView1.DataKeys[row.RowIndex].Value);
                Profile profile = new Profile(profileID); //instantiate profile
                profile.Delete(); //call delete method
                i++;
            }
        }
        if (i > 0)
        {
            //report success to UI
        }
    }
    catch (Exception ex)
    {
        //report error to UI
    }
}

在配置文件构造函数中,它通过打开连接,打开datareader然后设置对象的属性来保湿对象。我对代码中的using()块一丝不苟,所以每个数据库连接看起来都像这样:

using (SQLHelper db = new SQLHelper())
{
    db.AddParameterToSQLCommand("@ProfileID", SqlDbType.Int);
    db.SetSQLCommandParameterValue("@ProfileID", id);

    using (SqlDataReader dr = db.GetReaderByCmd("up_GetProfile"))
    {
        if (dr.Read())
        {
            _profileID = id;
            if (!dr.IsDBNull(0))
                ProfileName = dr.GetString(0);
            //... and so on
            return true;
        }
        else
        {
            return false;
        }
    }
}

一个datareader实现iDisposible,我的helper类也是如此,析构函数如下所示:

public void Dispose()
{
    try
    {
        //Clean Up Connection Object
        if (mobj_SqlConnection != null)
        {
            if (mobj_SqlConnection.State != ConnectionState.Closed)
            {
                mobj_SqlConnection.Close();
            }
            mobj_SqlConnection.Dispose();
        }

        //Clean Up Command Object
        if (mobj_SqlCommand != null)
        {
            mobj_SqlCommand.Dispose();
        }
    }

    catch (Exception ex)
    {
        throw new Exception("Error disposing data class." + Environment.NewLine + ex.Message);
    }
}

当我单步执行代码时,我发现连接总是被正确打开和关闭,我的堆栈永远不会超过五六次调用(我没有遇到任何递归问题)我已经确认我的所有数据访问代码使用块正确包装,但我的连接没有被释放回池中。相反,我得到了这个错误:

Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.

这发生在专用的应用程序池中,单个用户在10个以上的配置文件中执行删除操作。 似乎就像我正在做的一切正确但我不知道为什么连接没有被释放回池中。在 most 中,执行线程应该只打开两个连接,当它们超出范围时,它们都应该(并且!)处理。

我显然做错了什么但不能为我的生活找出什么。

2 个答案:

答案 0 :(得分:4)

从我的评论中,我将转换为答案。

看起来您正在尝试在Command对象之前关闭Connection对象,并且由于Command对象引用了连接,因此可能会使连接保持活动状态。

尝试切换它们:

//Clean Up Command Object
if (mobj_SqlCommand != null)
{
  mobj_SqlCommand.Dispose();
}

if (mobj_SqlConnection != null)
{
  if (mobj_SqlConnection.State != ConnectionState.Closed)
  {
    mobj_SqlConnection.Close();
  }
  mobj_SqlConnection.Dispose();
}

答案 1 :(得分:1)

如果我没记错的话,SqlHelper dispose不会自动关闭连接。你需要明确地关闭它。

我们总是在try / finally中包装我们对SqlHelper的使用,并在finally中显式调用close。