我是否需要在finally块中为SqlTransaction调用dispose?假装开发人员没有在任何地方使用USING,只需尝试/捕获。
SqlTransaction sqlTrans = con.BeginTransaction();
try
{
//Do Work
sqlTrans.Commit()
}
catch (Exception ex)
{
sqlTrans.Rollback();
}
finally
{
sqlTrans.Dispose();
con.Dispose();
}
答案 0 :(得分:11)
我是否需要使用
try-finally
或using
语句来处置SqlTransaction
?
拥有它并没有什么坏处。对于实现IDisposable的每个类都是如此,否则它将不会实现此接口。
但是,如果不再引用该对象,通常垃圾收集器会处理它。因为我也不想在每个第二个变量上调用dispose
或在任何地方使用using-statement,所以总是值得研究类Dispose
方法的实际实现。< / p>
protected override void Dispose(bool disposing)
{
if (disposing)
{
SNIHandle target = null;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
target = SqlInternalConnection.GetBestEffortCleanupTarget(this._connection);
if (!this.IsZombied && !this.IsYukonPartialZombie)
{
this._internalTransaction.Dispose();
}
}
catch (OutOfMemoryException e)
{
this._connection.Abort(e);
throw;
}
catch (StackOverflowException e2)
{
this._connection.Abort(e2);
throw;
}
catch (ThreadAbortException e3)
{
this._connection.Abort(e3);
SqlInternalConnection.BestEffortCleanup(target);
throw;
}
}
base.Dispose(disposing);
}
如果不了解所有(或任何事情)这里发生的事情,我可以说这不仅仅是一个简单的base.Dispose(disposing)
。因此,确保处理SqlTransaction可能是个好主意。
但是因为SqlConnection.BeginTransaction
创建了交易,所以reflect这也是一个好主意:
public SqlTransaction BeginTransaction(IsolationLevel iso, string transactionName)
{
SqlStatistics statistics = null;
string a = ADP.IsEmpty(transactionName) ? "None" : transactionName;
IntPtr intPtr;
Bid.ScopeEnter(out intPtr, "<sc.SqlConnection.BeginTransaction|API> %d#, iso=%d{ds.IsolationLevel}, transactionName='%ls'\n", this.ObjectID, (int)iso, a);
SqlTransaction result;
try
{
statistics = SqlStatistics.StartTimer(this.Statistics);
SqlTransaction sqlTransaction = this.GetOpenConnection().BeginSqlTransaction(iso, transactionName);
GC.KeepAlive(this);
result = sqlTransaction;
}
finally
{
Bid.ScopeLeave(ref intPtr);
SqlStatistics.StopTimer(statistics);
}
return result;
}
如你所见。创建事务时,GC还将使Connection保持活动状态。它也没有对事务的引用,因为它只返回它。因此,即使已经布置连接,也可能不会丢弃它。处理交易的另一个论点。
您可能还要查看TransactionScope
class,它比BeginTransaction
更安全。有关更多信息,请查看this question。
答案 1 :(得分:8)
在一般情况下,您构建或获取并拥有的每个IDisposable
对象都必须处置。
在特定情况下,有一些例外,但SqlTransaction
不是其中之一。
根据the documentation of SqlTransaction.Dispose
:
释放DbTransaction使用的非托管资源,并可选择释放托管资源。
(我的重点)
由于文档未声明在发出提交或回滚时释放了这些非托管资源,因此您需要处置此对象。
答案 2 :(得分:0)
我认为你可以关闭连接。我检查了BCL的代码 - 似乎连接处理它的事务 - 不需要明确地关闭它。