我有一个用于Sql或Oracle连接的IDbConnection。我没有问题打开它然后通过连接读取数据或保存数据。但是,当作业完成后,我尝试关闭连接。然后我得到一个例外:“内部.Net Framework数据提供程序错误1”。
以下是一些关闭连接的代码:
if (conn != null) // conn is IDbConnectin
{
if (conn.State == System.Data.ConnectionState.Open)
{
conn.Close(); // bung! exception
}
conn.Dispose();
}
conn = null;
在安全关闭连接之前我还应该检查一下吗?
答案 0 :(得分:2)
我知道它听起来可能不会直接解决您的问题,但IDbConnection是IDisposable,因此请在using {}
块中包装使用它的代码。
为什么?
您可能知道在using {}
块结束时,会调用Dispose()。并且,在IDbConnection的每个实例中,调用Dispose()将间接调用Close()。但是使用using
可以防止你完全遇到这个问题,你会得到额外的好处 - 使用using
,你被迫保持创造,开启,关闭和处置连接在同一上下文中。
我发现人们遇到问题的大多数问题是他们使用Finalizer或单独的线程来处理他们的连接对象。对我来说,还有一种更大的气味,他们将一次性物品保持活力一段时间,可能会分享同一类别的多个成员之间的联系。
换句话说,当你传递连接对象时,你可能会想写这样的东西:
class AccountService {
private IDbConnection conn;
internal AccountService(IDbConnection connection) {
this.conn = connection;
}
public Account GetAccount(String id) {
IDbCommand command = conn.CreateCommand();
conn.Open;
Account a = Account.FromReader(command.Execute(Strings.AccountSelect(id)));
conn.Close; // I remembered to call Close here
return a;
}
// ... other methods where I Open() and Close() conn
// hopefully not necessary since I've been careful to call .Close(), but just in case I forgot or an exception occured
~AccountService() {
if (conn != null)
{
if (conn.State == System.Data.ConnectionState.Open)
{
conn.Close();
}
conn.Dispose();
}
conn = null;
}
}
如果您使用过 using
,则根本不需要考虑使用Finalizer:
// IDbFactory is custom, and used to retrieve a Connection for a given Database
interface IDbFactory {
IDbConnection Connection { get; }
}
class AccountService {
private IDbFactory dbFactory;
internal AccountService(IDbFactory factory) {
this.dbFactory = factory;
}
public Account GetAccount(String id) {
using (IDbConnection connection = dbFactory.Connection) {
using (command = connection.GetCommand()) {
connection.Open();
return Account.FromReader(command.Execute(Strings.AccountSelect(id)));
}
} // via using, Close and Dispose are automatically called
}
// I don't need a finalizer, because there's nothing to close / clean up
}
using
规则有例外,特别是如果一次性物品的构造很昂贵,但是100次中有99次,如果你没有使用using
,那就有气味。 / p>
答案 1 :(得分:1)
我认为你在其他线程或Finilize方法中调用close方法。不要在类的Finalize方法中对Connection,DataReader或任何其他托管对象调用Close或Dispose。在终结器中,您应该只释放您的类直接拥有的非托管资源。如果您的类不拥有任何非托管资源,请不要在类定义中包含Finalize方法。见here