如何修复此代码中的SQL连接泄漏

本文关键字:SQL 连接 泄漏 何修复 代码 | 更新日期: 2023-09-27 18:25:31

我在我的网站上收到这个错误:

超时已过期。在获取来自池的连接。发生这种情况的原因可能是连接正在使用,已达到最大池大小。

描述:在执行期间发生未处理的异常当前web请求。请查看堆栈跟踪以了解更多信息有关错误的信息以及错误在代码中的来源。

异常详细信息:System.InvalidOperationException:超时已过期。从获取连接之前经过的超时时间水塘发生这种情况的原因可能是所有池连接都在已达到使用和最大池大小。

这是到处都在重用的C#类(我认为泄漏就在这里):

public class Generator
{
SqlConnection cn = null; // new SqlConnection(connectionString);
    public SqlConnection Connection {
        get {
            if (cn == null) {
            cn = new SqlConnection("Server=xxxxx,1433;Database=xxxxx;User ID=xxxxx;Password=xxxxx;Trusted_Connection=False;Encrypt=True;");
            }
            if(cn.State != ConnectionState.Open)
                cn.Open();
            return cn;
        }
    }
}

然后在我的方法中,我这样使用它:

        var cmd = _generator.Connection.CreateCommand();
        cmd.CommandText = "SELECT * FROM SomeTable";
        var reader = cmd.ExecuteReader();
        while (reader.Read())
        {
            //DO SOMETHING
        }
        reader.Close();

编辑:在我的方法类中,我试图在多个方法之间共享相同的SQL连接,如下所示:

private Generator _generator;
public HomeController()
{
    InitializeConnection();
}
private void InitializeConnection()
{
    _generator = new Generator();
}

有人能看到我如何修复泄漏吗?或者是什么导致了我的最大池问题?

如何修复此代码中的SQL连接泄漏

您需要using块来确保对象已被释放。

using (var cmd = _generator.Connection.CreateCommand()) {
    cmd.CommandText = "SELECT * FROM SomeTable";
    using (var reader = cmd.ExecuteReader()) {
            while (reader.Read())
            {
                //DO SOMETHING
            }
    }
}

我也不会使用Connection属性。最好根据需要打开和关闭连接,并允许连接池发挥作用。

连接没有关闭,只有读卡器。您可以将ExecuteReader与CommandBehavior.CloseConnection一起使用,但如果您使用ExecuteCommand,则没有这样有用的选项,并且您必须在连接对象上使用Close方法。

由于Generator类不是静态的,每次创建Generator()对象时,都会得到一个未关闭的新连接。你有几件事想做:

  • 将Generator类转换为Singleton模式,或将其完全删除
  • 让Generator实现IDisposable并调用cn.Dispose()
  • 确保每次调用Generator.Connection时都将其包装在using(…)块中

首先,Generator类拥有一个IDisposable对象(SqlConnection),因此应该实现IDisposaable本身。

接下来,使用下划线前缀(_generator.Connection.CreateCommand())表明_generator可能是其他数据访问类的一个字段,因此需要实现IDisposable本身。。。

根据您发布的代码,您需要删除Generator类,它似乎没有任何用处。

完成连接后,您需要处理它。

在你在问题中显示的代码中,我会这样做:

  1. 通过在部署生成器时部署连接对象,使Generator实现IDisposable
  2. 由于_generator看起来像一个字段,所以具有第二段代码的类可能还应该实现IDisposable并处理_generator的内容

此外,请注意,命令对象也在实现IDisposable,您应该始终处理您创建的实现IDisposable的对象。