32

我“继承”了一个小的 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();
}

你更喜欢什么,为什么?

马克

4

6 回答 6

19

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

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

于 2009-08-13T17:08:05.737 回答
10

我更喜欢 TransactionScope。它并非在每种情况下都能完美运行,但在您描述的情况下,它是更好的解决方案。

我的推理:

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

总之,结果是更少的代码和更健壮的设计,因为系统正在为我处理一些细节;这是我必须记住要做的一件事。

此外,当您在 DAL 中有许多嵌套方法时,透明的事务注册可能特别有用——尽管您必须小心不要意外地将您的事务变成需要 DTC 的分布式事务,如果发生这种情况,您使用多个 SqlConnections,即使它们指向同一个数据库。

于 2009-11-18T07:45:16.030 回答
8

Microsoft 建议使用事务范围:

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

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

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

编辑

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

编辑 2

同意下面对 Triynko 的评论。但是,我们使用实体框架,EF 将自动关闭并重新打开连接以将其加入事务。它不像物理上关闭连接,而是将其释放到连接池并获取一个新的,可以是相同的,也可以是不同的。

于 2009-08-13T13:08:40.700 回答
7

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

于 2009-11-18T00:55:07.687 回答
2

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

由于我现在有了更好的画面,在我目前SqlTransaction的基于方法遇到很多困难之后,我可能会改变支持TransactionScope,正如我所看到的......主要优点TransactionScope它可以很容易地在业务层中使用

于 2011-06-09T22:03:55.927 回答
2

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

于 2014-04-03T15:57:41.057 回答