重构ADO.NET - SqlTransaction与TransactionScope

mar*_*c_s 28 sql-server ado.net transactions transactionscope

我已经"继承"了一个C#方法,该方法创建了一个ADO.NET SqlCommand对象,并循环遍历要保存到数据库的项目列表(SQL Server 2005).

现在,使用传统的SqlConnection/SqlCommand方法,为了确保一切正常,两个步骤(删除旧条目,然后插入新条目)被包装到ADO.NET SqlTransaction中.

using (SqlConnection _con = new SqlConnection(_connectionString))
{
   using (SqlTransaction _tran = _con.BeginTransaction())
   {
      try
      {
         SqlCommand _deleteOld = new SqlCommand(......., _con);
         _deleteOld.Transaction = _tran;
         _deleteOld.Parameters.AddWithValue("@ID", 5);

         _con.Open();

         _deleteOld.ExecuteNonQuery();

         SqlCommand _insertCmd = new SqlCommand(......, _con);
         _insertCmd.Transaction = _tran;

         // add parameters to _insertCmd

         foreach (Item item in listOfItem)
         {
            _insertCmd.ExecuteNonQuery();
         }

         _tran.Commit();
         _con.Close();
       }
       catch (Exception ex)
       {
          // log exception
          _tran.Rollback();
          throw;
       }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,我最近一直在阅读很多关于.NET TransactionScope类的内容,我想知道,这里首选的方法是什么?通过切换使用,我可以获得任何东西(可读性,速度,可靠性)

using (TransactionScope _scope = new TransactionScope())
{
  using (SqlConnection _con = new SqlConnection(_connectionString))
  {
    ....
  }

  _scope.Complete();
}
Run Code Online (Sandbox Code Playgroud)

你更喜欢什么,为什么?

Joh*_*ers 16

您不会通过切换现有代码立即获得任何收益TransactionScope.由于它提供的灵活性,您应该将它用于未来的开发.它将使将ADO.NET调用以外的东西包含在事务中变得更加容易.

顺便说一句,在您发布的示例中,SqlCommand实例应该是using块.

  • 如果一个类实现了`IDisposable`,并且你创建了这个类的实例,那么你应该在它上面调用Dispose.最简单的方法是使用`using`块.我发现最好养成一直实施的习惯. (3认同)

Ric*_*kNZ 9

我更喜欢TransactionScope.它并不适用于所有场景,但在您描述的场景中,它是更好的解决方案.

我的推理:

  1. 在交易中登记是自动的
  2. 发生异常时的事务回滚是自动的

总之,结果是代码少一些,而且设计通常更加健壮,因为系统正在为我处理一些细节; 这是我必须记住的事情.

此外,当您在DAL中有许多嵌套方法时,透明的事务注册会特别有用 - 尽管您必须注意不要让您的事务变成需要DTC的分布式方法,如果您使用多个SqlConnections,即使它们指向同一个DB.


Shi*_*iji 8

Microsoft建议使用事务范围:

http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope.aspx

基本思想是事务范围将为您管理"环境事务上下文".首先,您与一个数据库交谈,您有一个SQL事务,然后您与数据库2进行通信,并将事务提升为分布式事务.

事务范围对您有用,因此您可以专注于系统的功能,而不是管道.

编辑

使用事务范围时,事务中涵盖该范围内的所有内容.因此,保存一行代码,将命令连接到事务.这可能是错误的来源,例如,如果在1000中有一个机会忘记了这一行,那么你会丢失多少.

编辑2

同意以下对Triynko的评论.但是,我们使用Entity Framework,EF会自动关闭并重新打开连接,以便在事务中登记它.它不会在物理上关闭连接,它会将其释放到连接池并获取一个新连接,它可以是相同的,也可以是不同的连接.

  • "当您使用事务范围时,该范围内的所有内容都将被事务覆盖." 不,一切都没有覆盖.只有在作用域中登记的连接上发出的命令才会受作用域的影响.如果在作用域中打开,则会自动在作用域中登记连接,否则在通过调用SqlConnection.EnlistTransaction创建连接之后,需要在作用域中手动登记已打开的连接.例如,如果您打开连接,则创建事务范围...您的任何命令都不会涉及事务. (12认同)

小智 6

只是注意使用事务范围有时我们会遇到很多问题,因为我们必须在服务器中设置许多设置,如设置DTC,防火墙等等.所以我建议使用SqlTransaction在实现中更省钱.