如何转换为ADO.NET事务而不是SQL Server事务?

Ian*_*oyd 2 sql-server ado.net transactions

现在我有使用预期方法在SQL Server上启动事务的代码:

ExecuteNonQuery(connection, "BEGIN TRANSACTION");
try
{
   DoABunchOnStuff(connection);
   DoSomeMoreStuff(connection);
   JustAFewMoreThings(connection);

   ExecuteNonQuery(connection, "COMMIT TRANSACTION");
} 
catch (Exception)
{  
   ExecuteNonQuery(connection, "ROLLBACK TRANSACTION");
   throw;
}
Run Code Online (Sandbox Code Playgroud)

现在我正在考虑调查使用ADO.NET提供的事务抽象的想法的可能性:

DbTransaction trans = connection.BeginTransaction();
try
{
   DoABunchOnStuff(connection);
   DoSomeMoreStuff(connection);
   JustAFewMoreThings(connection);

   trans.Commit();
} 
catch (Exception)
{  
   trans.Rollback();
   throw;
}
Run Code Online (Sandbox Code Playgroud)

从基于SQL Server的事务到ADO.NET事务的这种简单转换的问题是错误:

当分配给命令的连接处于挂起的本地事务中时,ExecuteNonQuery要求命令具有事务.该命令的Transaction属性尚未初始化.

我是否正确假设如果我想使用ADO.NET事务,我将不得不完全消除基础设施,将DbTransaction对象传递给在事务中执行或可能操作的每个方法?

Aar*_*ght 5

你是对的,但由于你显然一直保持连接打开,你可以用TransactionScope替换它; 只要只有一个开放连接,它就不会升级到DTC.

例:

using (TransactionScope tsc = new TransactionScope())
{
    DoABunchOnStuff(connection);
    DoSomeMoreStuff(connection);
    JustAFewMoreThings(connection);
    tsc.Complete();
}
Run Code Online (Sandbox Code Playgroud)

关于使用的注意事项TransactionScope:

  • 您必须确保包含Transaction Binding = Explicit Unbind在您的连接字符串中.默认情况下,事务以implicit-unbind模式运行,这意味着如果事务超时,它们将切换到自动提交模式.您几乎从不想要默认行为,因为它可能会干扰您的事务的原子性并导致某些人称之为数据损坏(即使它不是真正的"损坏").只要在连接字符串中使用正确的参数,就不必担心这一点.

  • TransactionScope如果范围内有多个连接,则会提升到DTC(分布式事务),包括链接的服务器和OPENROWSET.虽然这可能看起来像是不受欢迎的行为,但您的代码在任何其他方面都不会是事务安全的.BEGIN TRAN在多个连接上执行手动语句并将多个ROLLBACK语句放在异常处理程序中并不能确保整个事务的原子性.

  • 交易范围旨在嵌套,并自动计算开始新交易和在现有交易中加入的区别.这比匹配BEGIN TRANCOMMIT/ ROLLBACK语句更强大,因为后者依赖于连接本地事务计数,而前者实际上是... 作用域.使用TransactionScope类似于SQL Server中使用SAVE TRAN,TRY/ CATCH和命名的结构化事务处理ROLLBACK- 如果下游进程或过程淹没事务逻辑,则无需担心会发生什么,这在通过ADO 发送raw BEGINROLLBACK语句时是一个严重的风险.净.