C# 为什么这个'using'块不能释放数据库连接?
编辑: @Jeroen Mostert的评论效果很好:向连接字符串添加C# 为什么这个'using'块不能释放数据库连接?,c#,sql,postgresql,npgsql,C#,Sql,Postgresql,Npgsql,编辑: @Jeroen Mostert的评论效果很好:向连接字符串添加Pooling=false。正如他/她所指出的,我必须多读一些关于这种添加对整体性能的影响的文章 朗:C# 数据库管理系统:Postgres 在下面的代码中,使用两个连续的块(为了清楚起见,删除了很多) 在第一个using块中,在删除数据库camsdb之前,我最后一次连接到数据库并执行最后一次查询 查询完成后,代码使用块退出第一个,并应关闭数据库连接 不幸的是,第二个using块(应该删除第一个using块中刚连接到的数据
Pooling=false
。正如他/她所指出的,我必须多读一些关于这种添加对整体性能的影响的文章
- 朗:C#
- 数据库管理系统:Postgres
块(为了清楚起见,删除了很多)
在第一个using
块中,在删除数据库camsdb
之前,我最后一次连接到数据库并执行最后一次查询
查询完成后,代码使用
块退出第一个,并应关闭数据库连接
不幸的是,第二个using
块(应该删除第一个using块中刚连接到的数据库)无法删除数据库。postgresception
表示“还有一个会话正在使用数据库。”
但是,当我使用
块注释掉第一个时,第二个使用
块(履行其职责)会毫无问题地删除数据库。当代码到达相关的大括号时,使用block不是应该关闭连接吗?有没有办法强制垃圾收集器立即清理连接?(欢迎使用任何其他解决方案。)
M_SqlConn
类作为一个整体如下(我不想弄乱页面,这就是我最初没有粘贴它的原因):
我试过@Panagiotis的把戏,但没有成功。将if
块更改为以下内容,但这次程序停止给出“System.NullReferenceException:'对象引用未设置为对象的实例”。”
您没有为您的sqlConnection调用dispose。
请取消对此的注释
this.sqlConnection.Dispose();
并删除对方法CloseConnection()的调用
正如你在这里看到的
NpgsqlConnection是IDisposable的。当您为它调用Dispose时,它应该运行所有逻辑并关闭连接。编写将调用Close的包装器是不正确的。当你这样做的时候,它会有一个随机的行为
有一个问题,如果NpgsqlConnection是可以从盒子中IDisposable的,那么您真的需要自己的类,它本质上是一个包装器(或代理)?您当然已经知道了,但让我们来解决一些概念
在C#中使用意味着什么?
这意味着如果类实现了IDisposable
,则在对象实例生命周期结束时将调用Dispose()
方法
谁打开和关闭连接?
图书馆做这件事。您只需调用库公开的某个类的实例的某个方法,并希望它能为您完成这项工作
为什么要保持连接?
大多数情况下,您确实希望在应用程序中重复使用相同的连接,而且大多数情况下,这非常好,因为每个连接都会消耗资源。
这就是为什么我们有连接池
您能做些什么来缓解您的问题?
您可以按照注释中的建议尝试其他库。
或者查看TemaTre答案她/他看起来对特定的库有很好的了解
但也要注意,你正在做一些不同寻常的事情。
您确实有两个连接(和两个连接池?)。
一个用于“普通”用户查询数据库。
管理员删除数据库的第二个conn
我可以建议您首先将数据库置于单用户模式,并确保没有其他连接到它,甚至是应用程序外部的连接。您可以在删除数据库之前使用简单的SQL命令来实现它。什么是M_SqlConn
?那不是标准类型。你能给我看一下这门课吗?您是否编写代码来关闭Dispose方法中的连接?顺便说一句,垃圾收集器不是问题所在。这是您自己的Dispose
逻辑,或者Postgres数据库提供程序将(物理)连接保持在池中。对于特定连接,通常有几种方法可以关闭该功能,但这取决于所使用的连接库。(清除连接池是另一种方法,但这是局部问题的全局解决方案。)M_SqlConn
的任务是在退出using块时关闭连接。不过,很可能不需要这个类。自2006年以来,ADO.NET提供了数据库对象工厂。您甚至可以获得一个已经配置了连接字符串、凭据等的工厂。如果您发布了代码,则根本不调用sqlConnection.Close。无论是否打开,都应该调用sqlConnection.Dispose()。连接的工作是检查和维护其状态。所有教程和示例都显示了如何在使用
块中使用连接,因此,不仅可以在块上使用Dispose()
,而且它是唯一保证始终工作的方法。我已经粘贴了ConnectionClose
方法。更新我的answer@ssd不要用那种方法。改用Dispose()
。没有理由执行与Dispose()
相同的检查。@PanagiotisKanavos&TemaTre:让我试试。我会让你知道的,不!同样的问题依然存在,尽管我已经对整个if
块进行了注释,并将Close
连接任务完全留给了Npgsql。
using Npgsql;
using System;
using System.Text;
internal class M_SqlConn : IDisposable {
public Boolean connectionIsOpen = false;
private FormWarn formWarn = null;
private NpgsqlConnection sqlConnection = null;
private String hostAddress = "";
private String portNumber = "";
private String dbName = "";
private String roleName = "";
private String password = "";
internal M_SqlConn(String hostAddress, String portNumber, String dbName, String roleName, String password) {
this.hostAddress = hostAddress;
this.portNumber = portNumber;
this.dbName = dbName;
this.roleName = roleName;
this.password = password;
this.ConnectionOpen();
return;
}
private void ConnectionOpen() {
StringBuilder exceptionString = new StringBuilder(String.Empty);
NpgsqlConnectionStringBuilder connectionStringBuilder = new NpgsqlConnectionStringBuilder {
Host = this.hostAddress,
Port = Convert.ToInt32(this.portNumber),
Database = this.dbName,
Username = this.roleName
};
this.sqlConnection = new NpgsqlConnection(connectionStringBuilder.ToString() + $";Password={this.password}");
try {
this.sqlConnection.Open();
if (this.sqlConnection.State == System.Data.ConnectionState.Open) {
this.connectionIsOpen = true;
}
}
catch (PostgresException e) {
exceptionString.AppendLine(
$"{Environment.NewLine}" +
$"Postgres Exception{Environment.NewLine}" +
$"{e.ToString()}{Environment.NewLine}");
}
catch (NpgsqlException e) {
exceptionString.AppendLine(
$"{Environment.NewLine}" +
$"Npgsql Exception{Environment.NewLine}" +
$"{e.ToString()}{Environment.NewLine}");
}
catch (Exception e) {
exceptionString.AppendLine(
$"{Environment.NewLine}" +
$"General Exception{Environment.NewLine}" +
$"{e.ToString()}{Environment.NewLine}");
}
if (!this.connectionIsOpen) {
this.FormWarn_ShowDialog(FormWarn.FormType.Error, exceptionString.ToString());
}
return;
}
private void ConnectionClose() {
StringBuilder exceptionString = new StringBuilder(String.Empty);
if (this.sqlConnection != null) {
try {
this.sqlConnection.Close();
this.connectionIsOpen = false;
}
catch (PostgresException e) {
exceptionString.AppendLine(
$"{Environment.NewLine}" +
$"Postgres Exception{Environment.NewLine}" +
$"{e.ToString()}{Environment.NewLine}");
}
catch (NpgsqlException e) {
exceptionString.AppendLine(
$"{Environment.NewLine}" +
$"Npgsql Exception{Environment.NewLine}" +
$"{e.ToString()}{Environment.NewLine}");
}
catch (Exception e) {
exceptionString.AppendLine(
$"{Environment.NewLine}" +
$"General Exception{Environment.NewLine}" +
$"{e.ToString()}{Environment.NewLine}");
}
if (this.connectionIsOpen) {
this.FormWarn_ShowDialog(FormWarn.FormType.Error, exceptionString.ToString());
}
else {
this.sqlConnection.Dispose();
this.sqlConnection = null;
}
}
return;
}
public Boolean SqlCommandExecuteNonQuery(String sqlString) {
Boolean commandStatus = false;
StringBuilder exceptionString = new StringBuilder(String.Empty);
using (NpgsqlCommand sqlCommand = new NpgsqlCommand(sqlString, this.sqlConnection)) {
try {
sqlCommand.ExecuteNonQuery();
commandStatus = true;
}
catch (PostgresException e) {
exceptionString.AppendLine(
$"{Environment.NewLine}" +
$"Postgres Exception{Environment.NewLine}" +
$"{e.ToString()}{Environment.NewLine}");
}
catch (NpgsqlException e) {
exceptionString.AppendLine(
$"{Environment.NewLine}" +
$"Npgsql Exception{Environment.NewLine}" +
$"{e.ToString()}{Environment.NewLine}");
}
catch (Exception e) {
exceptionString.AppendLine(
$"{Environment.NewLine}" +
$"General Exception{Environment.NewLine}" +
$"{e.ToString()}{Environment.NewLine}");
}
};
if (!commandStatus) {
exceptionString.AppendLine(
$"{Environment.NewLine}" +
$"Sql string is:{Environment.NewLine}" +
$"{sqlString}{Environment.NewLine}");
this.FormWarn_ShowDialog(FormWarn.FormType.Error, exceptionString.ToString());
}
return (commandStatus);
}
public Int32 SqlCommandExecuteScalar(String sqlString) {
Int32 count = -1;
StringBuilder exceptionString = new StringBuilder(String.Empty);
using (NpgsqlCommand sqlCommand = new NpgsqlCommand(sqlString, this.sqlConnection)) {
try {
Int32 countTmp = Convert.ToInt32(sqlCommand.ExecuteScalar());
count = countTmp;
}
catch (PostgresException e) {
exceptionString.AppendLine(
$"{Environment.NewLine}" +
$"Postgres Exception{Environment.NewLine}" +
$"{e.ToString()}{Environment.NewLine}");
}
catch (NpgsqlException e) {
exceptionString.AppendLine(
$"{Environment.NewLine}" +
$"Npgsql Exception{Environment.NewLine}" +
$"{e.ToString()}{Environment.NewLine}");
}
catch (Exception e) {
exceptionString.AppendLine(
$"{Environment.NewLine}" +
$"General Exception{Environment.NewLine}" +
$"{e.ToString()}{Environment.NewLine}");
}
};
if (count == -1) {
exceptionString.AppendLine(
$"{Environment.NewLine}" +
$"Sql string is:{Environment.NewLine}" +
$"{sqlString}{Environment.NewLine}");
this.FormWarn_ShowDialog(FormWarn.FormType.Error, exceptionString.ToString());
}
return (count);
}
public NpgsqlDataReader SqlCommandExecuteQuery(String sqlString) {
NpgsqlDataReader dataReader = null;
StringBuilder exceptionString = new StringBuilder(String.Empty);
using (NpgsqlCommand sqlCommand = new NpgsqlCommand(sqlString, this.sqlConnection)) {
try {
dataReader = sqlCommand.ExecuteReader();
}
catch (PostgresException e) {
exceptionString.AppendLine(
$"{Environment.NewLine}" +
$"Postgres Exception{Environment.NewLine}" +
$"{e.ToString()}{Environment.NewLine}");
}
catch (NpgsqlException e) {
exceptionString.AppendLine(
$"{Environment.NewLine}" +
$"Npgsql Exception{Environment.NewLine}" +
$"{e.ToString()}{Environment.NewLine}");
}
catch (Exception e) {
exceptionString.AppendLine(
$"{Environment.NewLine}" +
$"General Exception{Environment.NewLine}" +
$"{e.ToString()}{Environment.NewLine}");
}
};
if (exceptionString.Length > 0) {
exceptionString.AppendLine(
$"{Environment.NewLine}" +
$"Sql string is:{Environment.NewLine}" +
$"{sqlString}{Environment.NewLine}");
this.FormWarn_ShowDialog(FormWarn.FormType.Error, exceptionString.ToString());
}
return (dataReader);
}
private void FormWarn_ShowDialog(FormWarn.FormType formType, String msg) {
using (this.formWarn = new FormWarn(formType, msg)) {
this.formWarn.ShowDialog();
}
this.formWarn.Dispose();
this.formWarn = null;
return;
}
public void Dispose() {
if (this.formWarn != null) {
this.formWarn.Dispose();
this.formWarn = null;
}
if (this.connectionIsOpen) {
this.ConnectionClose();
}
this.hostAddress = "";
this.portNumber = "";
this.dbName = "";
this.roleName = "";
this.password = "";
return;
}
}
if (this.sqlConnection.State == System.Data.ConnectionState.Open) {
this.sqlConnection.Dispose(); // exception here
this.sqlConnection = null;
}
this.sqlConnection.Dispose();