我是否需要使用try-finally
或using
-statement 来处理SqlTransaction
?
拥有它并没有什么坏处。对于每个实现IDisposable的类都是如此,否则它不会实现这个接口。
但通常垃圾收集器处理未引用的对象(这并不意味着 GC 调用 dispose,这不是真的),因此您只需要它来处理非托管资源。但是因为我也不想调用dispose
所有其他变量或到处使用using 语句,所以研究类方法的实际实现总是值得的Dispose
。
SqlTransaction.Dispose
:
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
这一点也可能是一个好主意:
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也会在创建 Transaction 时保持 Connection 处于活动状态。它也不包含对事务的引用,因为它只返回它。因此,即使连接已经被释放,它也可能不会被释放。处置交易的另一个论据。
您可能还会TransactionScope
查看比BeginTransaction
. 查看此问题以获取更多信息。