如何修复此代码中的SQL连接泄漏?
我在我的网站上发现了这个错误:如何修复此代码中的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();
}
任何人都可以看到我如何解决泄漏或什么导致我的最大池问题?
您需要using
块以确保对象被丢弃。
using (var cmd = _generator.Connection.CreateCommand()) {
cmd.CommandText = "SELECT * FROM SomeTable";
using (var reader = cmd.ExecuteReader()) {
while (reader.Read())
{
//DO SOMETHING
}
}
}
我也不会使用Connection
属性。根据需要打开和关闭连接会更好,并允许连接池完成其工作。
你在这里专注于错误的对象,而命令对象实现了IDisposable,当然应该处理掉,他很可能不会处理存储在'Generator '实例,并将其留给GC。 – 2012-02-22 16:05:17
@ LasseV.Karlsen:是的,但他只有一个连接,除非他有多个'_generator'实例。另外,我确实告诉他我不会使用'Connection'属性。 – 2012-02-22 16:06:39
我正在尝试重新使用私人成员。我更新了我如何初始化私人会员的问题。 – TruMan1 2012-02-22 16:10:38
连接没有关闭,只有读者。您可以将ExecuteReader与CommandBehavior.CloseConnection一起使用 - 但是如果您使用ExecuteCommand,则没有这种有用的选项,您必须在连接对象上使用Close方法。
当你完成它时,你需要处理连接。
在你的代码中的问题已经证明,这里就是我会做:
- 让
Generator
通过连接对象的处置实施IDisposable
当发电机布置 - 由于
_generator
看起来像场,与第二部分的代码的类可能应该也实现了IDisposable
和处置_generator
内容
而且,请注意,该命令对象也在执行IDisposable
,您应该始终处理实现您创建的IDisposable
的对象。
首先,您的Generator类拥有一个IDisposable对象(一个SqlConnection),所以应该实现IDisposable本身。
下一页您的下划线前缀(_generator.Connection.CreateCommand()
)的使用表明,_generator可能是你其他数据访问类,因此需要实现IDisposable自己,的场......根据您的代码
发布时,您需要删除类似Generator
的类,这看起来没有任何用处。
由于您的Generator类不是静态的,因此每次创建Generator()对象时都会得到一个未关闭的新连接。你已经得到了你想要做的几件事情:
- 将您生成类Singleton模式,或者删除它完全
- 有无发电机实现IDisposable并调用cn.Dispose()
- 确保每个你打电话给发电机。连接,你把它包在一个使用(...)块
不是ac#开发人员,但不应该是'this.cn'或类似的,以表明cn是一个类变量,而不仅仅是连接方法中的局部变量? – 2012-02-22 16:01:28
您并未在任何地方关闭连接。 – Oded 2012-02-22 16:01:55
@MarcB - 如果引用不含糊,则不需要用'this'限定变量。 – Oded 2012-02-22 16:02:42