65.9K
CodeProject 正在变化。 阅读更多。
Home

.NET 1.1 中的 TransactionScope

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.57/5 (7投票s)

2005 年 6 月 1 日

1分钟阅读

viewsIcon

100958

在 .NET 1.1 中模拟 .NET 2.0 中即将推出的 TransactionScope 功能。

现在:使用 ServicedComponent 实现声明式数据库事务

自 Windows NT 4.0 时代起,使用 Microsoft SQL Server 的开发人员就享受到了声明式事务处理。在 .NET Framework 中,这意味着通常我们需要从 ServicedComponent 类继承,将 TransactionAttribute 应用到它,并使用 SetAbort/SetComplete 方法来通知框架我们的数据库操作是否成功或失败。框架负责处理剩下的事情。

简单吗?是的,但是…

  • ServicedComponent 要求您对程序集进行签名,许多开发人员认为这步是不必要的复杂化
  • 您无法在一个类中混合事务性和非事务性方法,这会强制您将单个逻辑 CustomerService 分割为 CustomerReaderCustomerWriter 或类似的东西。

未来:.NET 2.0 中的 TransactionScope

在 .NET 2.0 中,我们将拥有 TransactionScope 类,它解决了这两个问题。它用作围绕必须在数据库事务内运行的代码的大括号,虽然不再是声明式风格,但它提供了一个简洁明了的模型。

using (TransactionScope scope = new TransactionScope())
{
  // open connection
  // perform database operation, which is going to run inside the transaction// call other method and if the other method creates a TransactionScope object
  // it will share the transaction with the current method

  // All is well:
  Scope.Complete();
}

未来已来

好的,上面的代码看起来像我希望的那样,但是 Whidbey 离我的生产机器还有一年的时间。我必须使用 .NET 1.1 创建我自己的解决方案,这就是它。事实上,实现非常简单,我现在为自己没有早点弄清楚而感到羞愧!

用法

using (TransactionScope scope = new TransactionScope())
using (SqlConnection conn = new SqlConnection(connString))
using (SqlCommand cmd = new SqlCommand(updateSql, conn))
{
  System.Diagnostics.Debug.Assert(
         System.EnterpriseServices.ContextUtil.IsInTransaction);
    
  conn.Open();
    
  int result = cmd.ExecuteNonQuery();

  // We call it success if exactly one record was updated:
  if (result == 1)
  {
    scope.Complete();
  }
}

这是完整的类

// Copyright (c) 2005 Alexander Shirshov
//
// This code is free software; you can redistribute it and/or modify it.
// However, this header must remain intact and unchanged. Additional
// information may be appended after this header. Publications based on
// this code must also include an appropriate reference.
// 
// This code is distributed in the hope that it will be useful, but 
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
// or FITNESS FOR A PARTICULAR PURPOSE.

using System;
using System.EnterpriseServices;

namespace Omnitalented.EnterpriseServices
{
  public class TransactionScope : IDisposable
  {
    private bool succeded;

    public TransactionScope() : this(TransactionOption.Required, 
                                TransactionIsolationLevel.Any, 60)
    {
    }

    public TransactionScope(TransactionOption transactionOption) : 
           this(transactionOption, TransactionIsolationLevel.Any, 60)
    {
    }

    public TransactionScope(TransactionOption transactionOption, 
           TransactionIsolationLevel isolationLevel, int timeoutSeconds)
    {
      ServiceConfig cfg = new ServiceConfig();
      cfg.Transaction = transactionOption;
      cfg.IsolationLevel = isolationLevel;
      cfg.TransactionTimeout = timeoutSeconds;
            
      ServiceDomain.Enter(cfg);
    }

    public void Complete()
    {
      succeded = true;
    }

    public void Dispose()
    {
      if (succeded)
      {
        ContextUtil.SetComplete();
      } 
      else
      {
        ContextUtil.SetAbort();
      }
      ServiceDomain.Leave();
    }
  }
}

请注意:该代码仅适用于 Windows 2003 Server 或 Windows XP;这是 System.EnterpriseServices.ServiceDomain 类的要求。

© . All rights reserved.