问题描述
我需要在 SqlTransaction 的 finally 块中调用 dispose 吗?假设开发者没有在任何地方使用 USING,只是尝试/捕获.
Do I need to call dispose in the finally block for SqlTransaction? Pretend the developer didnt use USING anywhere, and just try/catch.
SqlTransaction sqlTrans = con.BeginTransaction();
try
{
//Do Work
sqlTrans.Commit()
}
catch (Exception ex)
{
sqlTrans.Rollback();
}
finally
{
sqlTrans.Dispose();
con.Dispose();
}
推荐答案
我是否需要使用
try-finally
或using
-statement 来处理SqlTransaction
?
Do I need to use
try-finally
or theusing
-statement to dispose theSqlTransaction
?
拥有它并没有什么坏处.对于实现 IDisposable 的每个类都是如此,否则它会不实现这个接口.
It does not hurt to have it. This is true for every class implementing IDisposable, otherwise it would not implement this interface.
但通常垃圾收集器处理未引用的对象(这并不意味着 GC 调用了 dispose,这 不正确),因此您只需要非托管资源.但是因为我也不想在所有其他变量上调用 dispose
或使用 using-statement 无处不在,研究类的 Dispose
方法的实际实现总是值得的.
But normally the garbage collector deals with unreferenced objects(it doesn't mean that the GC calls dispose, which isn't true), so you need it only for unmanaged resources. But because i also don't want to call dispose
on every other variable or use the using-statement everywhere, it it's always worth to look into the actual implementation of the class' Dispose
method.
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 被释放可能是一个好主意.
Without understanding all(or anything) what is happening here i can say that this is more than a simple base.Dispose(disposing)
. So it might be a good idea to ensure that a SqlTransaction gets disposed.
但是因为 SqlConnection.BeginTransaction
创建了事务,所以 反映这一点:
But because SqlConnection.BeginTransaction
creates the transaction it could also be a good idea to reflect this also:
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'
", 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 还将在创建事务时保持连接处于活动状态.它也不持有对交易的引用,因为它只返回它.因此,即使连接已被处理,它也可能不会被处理.处理交易的另一个论据.
As you can see. The GC will also keep the Connection alive when a Transaction is created. It also doesn't hold a reference to the transaction since it only returns it. Hence it might not be disposed even when the connection is already disposed. Another argument to dispose the transaction.
您还可以查看TransactionScope
类 比 BeginTransaction
更安全.查看这个问题了解更多信息.
You might also have a look at the TransactionScope
class which is more fail-safe than BeginTransaction
. Have a look at this question for more informations.
这篇关于SqlTransaction 是否需要调用 Dispose?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!