重构ADO.NET - SqlTransaction与TransactionScope

时间:2009-08-13 09:29:53

标签: 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;
       }
    }
}

现在,我最近一直在阅读有关.NET TransactionScope课程的很多内容,我想知道,这里的首选方法是什么?通过切换到使用

,我可以获得任何东西(可读性,速度,可靠性)
using (TransactionScope _scope = new TransactionScope())
{
  using (SqlConnection _con = new SqlConnection(_connectionString))
  {
    ....
  }

  _scope.Complete();
}

您更喜欢什么,为什么?

马克

6 个答案:

答案 0 :(得分:16)

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

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

答案 1 :(得分:8)

Microsoft建议使用事务范围:

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

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

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

修改

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

编辑2

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

答案 2 :(得分:8)

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

我的推理:

  1. 交易中的登记是自动的
  2. 发生异常时的事务回滚是自动的
  3. 由于系统正在为我处理一些细节,因此结果是代码少了一些,而且设计通常更加健壮。这是我必须记住的事情。

    此外,如果您的DAL中有许多嵌套方法,透明的交易注册会特别有用 - 尽管您必须注意不要让您的交易变成需要DTC的分布式方法,如果您使用多个SqlConnections,即使它们指向同一个数据库,也会发生这种情况。

答案 3 :(得分:6)

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

答案 4 :(得分:2)

好吧,也许为时已晚......但无论如何,我会为那些感兴趣的人写下来......

由于我现在有一个更好的图片,在我目前基于SqlTransaction的方法遇到很多困难之后,我可能会更改为TransactionScope,正如我所看到的那样... ... TransactionScope可以在业务层中轻松使用

答案 5 :(得分:2)

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