当您为SQL连接,事务和命令创建“使用”块时,众所周知,使用块关联的连接,事务或命令在您离开使用块后会自行处理.
如果在其中一个块中发生异常,例如在命令块中 – 事务是否会自行回滚,或者开发人员是否需要在命令’using’块内执行try catch,并添加回滚抓住这个尝试的事务声明?
最佳答案 它不能保证被处置. SqlTransaction的Dispose(bool)方法实际上会有条件地回滚它:
// System.Data.SqlClient.SqlTransaction
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);
}
如果你注意到,只有当这个._internalTransaction.Dispose();被叫了.这里的问题是,如果GetBestEffortCleanupTarget抛出异常,它将不会被清除.
在你的情况下,只要没有按照已经说明的方式抛出异常,你将属于Zombied类,因此它将在_internalTransaction.Dispose()调用中实际发出一个Rollback调用.
最后,如果用false调用它,肯定不会被处理掉.
现在,除非我真的在这里遗漏了一些东西,否则我对这段代码的脆弱程度感到有些震惊.
一个有趣的说明是,我认为MSDN文档实际上是错误的,因为它声明了Rollback()
方法:
The transaction can only be rolled back from a pending state (after BeginTransaction has been called, but before Commit is called). The transaction is rolled back in the event it is disposed before Commit or Rollback is called.