关于sql server:重构ADO.NET – SqlTransaction与TransactionScope

Refactoring ADO.NET - SqlTransaction vs. TransactionScope

我"继承"了一个小c方法,它创建了一个ado.net sqlcommand对象,并循环访问要保存到数据库中的项目列表(SQL Server 2005)。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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;
       }
    }
}

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

1
2
3
4
5
6
7
8
9
using (TransactionScope _scope = new TransactionScope())
{
  using (SqlConnection _con = new SqlConnection(_connectionString))
  {
    ....
  }

  _scope.Complete();
}

你想要什么?为什么?

马克


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

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


我更喜欢交易范围。它并不是在每一个场景中都能完美地工作,但在你描述的场景中,它是更好的解决方案。

我的推理:

  • 事务中的登记是自动的
  • 异常情况下的事务回滚是自动的
  • 总之,结果是代码少了一点,设计总体上更健壮,因为系统为我处理了一些细节;这是我必须记住的少一件事。

    此外,当DAL中有许多嵌套方法时,透明事务注册特别有用——尽管您必须注意不要意外地将事务转换为需要DTC的分布式方法,但如果使用多个sqlconnections,即使它们指向同一个DB,也会发生这种情况。


    Microsoft建议使用事务范围:

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

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

    事务范围确实适用于您,因此您可以将精力集中在系统的功能上,而不是管道。

    编辑

    当您使用事务范围时,该范围内的所有内容都由事务覆盖。因此,保存一行代码,将命令连接到事务。这是一个可能的错误源,例如,如果这一行被忽略的概率为1000,那么您会丢失多少。

    编辑2

    同意下面对triynko的评论。但是,我们使用实体框架,EF将自动关闭并重新打开连接,以便将其登记到事务中。它不会像物理上那样关闭连接,而是将其释放到连接池中并获得一个新的连接,可以是同一个连接池,也可以是不同的连接池。


    请注意,使用事务作用域有时会有很多问题,因为在服务器中必须进行许多设置,如设置DTC、防火墙等,所以我建议使用sqlTransaction更节省实现。


    也晚了…即使数据库不支持嵌套事务,您也可以在业务层中轻松地拥有"嵌套"事务。.NET控制嵌套并最终使用一个数据库事务(至少在SQL Server 2008+的情况下)。这使得将数据访问代码作为更大事务的一部分在其原始意图之外重用变得更加容易。


    好吧,也许太晚了…但不管怎样,我会把它写下来给那些感兴趣的人…

    既然我现在有了一个更好的画面,在我目前基于SqlTransaction的方法遇到了很多困难之后,我可能会改变这种方法,转而支持TransactionScope,正如我所见……TransactionScope的主要优点是它可以很容易地在业务层中使用。