2012-02-22 58 views
0

我在我的网站上发现了这个错误:如何修复此代码中的SQL连接泄漏?

超时已过期。在从池中获取 连接之前已经超时。可能发生了这种情况,因为所有连接池都正在使用中,并且已达到最大池大小。

描述:在执行 当前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(); 
} 

任何人都可以看到我如何解决泄漏或什么导致我的最大池问题?

+0

不是ac#开发人员,但不应该是'this.cn'或类似的,以表明cn是一个类变量,而不仅仅是连接方法中的局部变量? – 2012-02-22 16:01:28

+0

您并未在任何地方关闭连接。 – Oded 2012-02-22 16:01:55

+0

@MarcB - 如果引用不含糊,则不需要用'this'限定变量。 – Oded 2012-02-22 16:02:42

回答

6

您需要using块以确保对象被丢弃。

using (var cmd = _generator.Connection.CreateCommand()) { 
    cmd.CommandText = "SELECT * FROM SomeTable"; 
    using (var reader = cmd.ExecuteReader()) { 

      while (reader.Read()) 
      { 
       //DO SOMETHING 
      } 
    } 
} 

我也不会使用Connection属性。根据需要打开和关闭连接会更好,并允许连接池完成其工作。

+3

你在这里专注于错误的对象,而命令对象实现了IDisposable,当然应该处理掉,他很可能不会处理存储在'Generator '实例,并将其留给GC。 – 2012-02-22 16:05:17

+0

@ LasseV.Karlsen:是的,但他只有一个连接,除非他有多个'_generator'实例。另外,我确实告诉他我不会使用'Connection'属性。 – 2012-02-22 16:06:39

+0

我正在尝试重新使用私人成员。我更新了我如何初始化私人会员的问题。 – TruMan1 2012-02-22 16:10:38

4

连接没有关闭,只有读者。您可以将ExecuteReaderCommandBehavior.CloseConnection一起使用 - 但是如果您使用ExecuteCommand,则没有这种有用的选项,您必须在连接对象上使用Close方法。

1

当你完成它时,你需要处理连接。

在你的代码中的问题已经证明,这里就是我会做:

  1. Generator通过连接对象的处置实施IDisposable当发电机布置
  2. 由于_generator看起来像场,与第二部分的代码的类可能应该也实现了IDisposable和处置_generator内容

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

2

首先,您的Generator类拥有一个IDisposable对象(一个SqlConnection),所以应该实现IDisposable本身。

下一页您的下划线前缀(_generator.Connection.CreateCommand())的使用表明,_generator可能是你其他数据访问类,因此需要实现IDisposable自己,的场......根据您的代码

发布时,您需要删除类似Generator的类,这看起来没有任何用处。

3

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

  • 将您生成类Singleton模式,或者删除它完全
  • 有无发电机实现IDisposable并调用cn.Dispose()
  • 确保每个你打电话给发电机。连接,你把它包在一个使用(...)块