在.net中本来就可以直接使用Com+事务啦,为什么一定要自已实现呢?设计的原则之一:不要重复发明轮子!

解决方案 »

  1.   

    你再说什么,2001年就出版了“精通.net的COM+”了……
      

  2.   

    ASP.NET Web 服务或通过 .NET Remoting 提供的对象可以使用本地事务根据单个数据库协调工作。如果需要根据多个资源协调工作,它可以使用 .NET 企业服务(也称为 COM+)公布的事务(由 COM+ 管线管理的 DTC 分布式事务)。但要注意的是,ASP.NET Web 服务和 .NET Remoting 管线都不能传播公布的事务,因此两种端点都不可能通过跨进程的调用继承公布的事务。 
       
      这不一定是件坏事。一般来讲,公布的事务比本地事务代价要高,而要跨进程传播公布的事务,则代价会更高。如果您确实需要这种功能,简单的解决方案是在 .NET 企业服务服务器应用程序中展开一个从 System.EnterpriseServices.ServicedComponent 中衍生的类(有关详细信息,请参阅 COM+ Integration: How .NET Enterprise Services Can Help You Build Distributed Applications [英文])。对该类对象的跨进程调用将使用 DCOM 进行处理,以确保正确传播事务环境。较难的解决方案是使用底层的 API,手动传播分布的事务。 
       
      值得注意的是,传统的分布式事务模型一般不适用于松散耦合的 Web 服务。基于补偿事务的模型(即,撤消其他事务所提交工作的事务)更有意义,因为其隔离约束条件并不是很严格。在包括 Microsoft 的 Web 服务供应商中有一种普遍的说法,即 Web 服务空间需要的事务模型越灵活,该空间中进行的工作越多。等到定义出 Web 服务事务的标准方法时,您就可以根据情况使用本地或公布的事务实现自己的补偿架构了。 
       
      选择体系结构 
      如果您正在设计一个基于 .NET 的分布式应用程序,则需要考虑本文中讨论的所有问题,并对系统体系结构的应有结果得出一些结论。一般来讲,这比您想像的要容易些。但总有一些特殊的情况需要其他的方法,以下是您可以进行的某些一般假设,可为您简化情况。 
       
      首先,在默认情况下使用 ASP.NET Web 服务。它们的执行和使用都很简单,可以为客户端平台提供尽可能宽的使用范围,而且可以从默认安全性策略下沙箱中运行的代码中调用 ASP.NET Web 服务客户端代理代码。 
       
      如果要使用较传统的带有 CLR 类型保真度的分布式对象模型,不需要与其他平台进行互操作,而且由您控制客户端和服务器的配置,请考虑使用 .NET Remoting。如果您选择 .NET Remoting,最好使 HTTP 通道与 IIS 和 ASP.NET 集成,否则,必须建立自己的进程生命周期管理和安全性基础结构。假定 .NET Remoting 需要 .NET 客户端,使用二进制格式化程序而不是 SOAP 格式化程序是很有意义的;互操作性将不成问题,而且性能将显著提高。 
       
      最后,如果需要公布的事务,请使用企业服务 (COM+)。如果您执行 ServicedComponents,则出于性能方面的考虑,默认情况下它们将部署在库应用程序中。如果它们需要在远程计算机上运行,则将它们部署在服务器应用程序中。(如果您需要执行不同的进程安全性令牌 [而不是 aspnet_wp.exe 使用的令牌] 的代码,即使在相同的计算机上,可能也要考虑使用 COM+ 服务器应用程序。) 
       
      以下是三个基于这些理念的公共体系结构。 
       
       
       
      图 1:简单的 3 层体系结构 
       
      图 1 显示了一个简单的 3 层体系结构,它带有 Web 服务器领域,支持一系列不同的客户端。所有服务器端的代码都在 ASP.NET 辅助进程 aspnet_wp.exe 中执行。这三种不同类型的客户端可以使用 HTTP 访问服务器领域。基于浏览器的客户端调用 ASP.NET Web 页面;多客户端(如 Windows 窗体应用程序、Microsoft® Visual Basic® 6 应用程序)和其他 Web 服务使用 ASP.NET Web 服务;根据需要,.NET 多客户端(如 Windows 窗体应用程序)和 Web 服务使用 ASP.NET Web 服务,或使用 HTTP 通道和二进制格式化程序的 .NET Remoting(假定它不在沙箱中)。 
       
      图 2:使用 ASP.NET 的 n 层体系结构 
       
      一些非常大的应用程序使用一套辅助计算机从 Web 服务器的外层分担工作。这种体系结构如图 2 所示。请注意,在这种情况下,第二层也通过 ASP.NET 提供功能。 
       
      图 3:使用企业服务 (COM+) 的 n 层体系结构 
       
      图 3 显示此体系结构的另一种版本,其第二层使用在 COM+ 中部署的 ServicedComponents 提供功能。 
       
      显然,这些并不是 .NET Framework 所支持的所有可能的体系结构。但是,它为您设计自己的系统提供了适当的基础。 
       
      小结 
      虽然 .NET Remoting 基础结构和 ASP.NET Web 服务都可以进行跨进程通信,但每种设计适用于不同的用户。ASP.NET Web 服务的编程模型很简单,使用范围很广。.NET Remoting 的编程模型较复杂,使用范围较窄。请务必了解这两种技术的工作原理,并选择适合您应用程序的技术。在任意一种情况下,都要使用 IIS 和 ASP.NET 管理进程生命周期,并提供一般的安全性。
      

  3.   

    我寫的一個實例
    using System;
    using System.EnterpriseServices;
    using System.Data;
    using System.Data.SqlClient;
    using System.Data.OleDb;
    using System.Runtime.InteropServices;
    using System.Collections;
    using ItemInfo;namespace MyControls.ComServices.Transaction
    {
    public interface IBusiness
    {
    DataSet QueryShop();
    DataSet QueryBank();
    void Buy(string sCardNO , ArrayList Arr);
    void ReduceCreditAmount(string sCardNO , int nCost , OleDbCommand cmd);
    void ReduceShopStock(string sWareNO , int nCount , OleDbCommand cmd);
    }    [Transaction(TransactionOption.Required)]
    [ObjectPooling(Enabled = true , MinPoolSize = 1 , MaxPoolSize = 50 , CreationTimeout = 60)]
    public class BusinessClass : ServicedComponent,IBusiness
    {
    public BusinessClass()
    {
    }
    //查詢商店
    public DataSet QueryShop()
    {
    DataSet oDs = new DataSet();
                string sConnShop = "Provider=sqloledb;Data Source=JANE;Initial Catalog=Shop;User Id=sa;";
    OleDbConnection ConnShop = new OleDbConnection(sConnShop);
    string sCmd = "SELECT WARENO , NUM FROM WARE";
    OleDbDataAdapter OleAda = new OleDbDataAdapter(sCmd , ConnShop);
    ConnShop.Open();
    OleAda.Fill(oDs);
    ConnShop.Close();
    return oDs;
    }
    //查詢銀行
    public DataSet QueryBank()
    {
    DataSet oDs = new DataSet();
    string sConnBank = "Provider=sqloledb;Data Source=JANE;Initial Catalog=Bank;User Id=sa;";
    OleDbConnection ConnBank = new OleDbConnection(sConnBank);
    string sCmd = "SELECT CREDIT_NO , AMOUNT FROM CREDIT_INFO";
    OleDbDataAdapter OleAda = new OleDbDataAdapter(sCmd , ConnBank);
    ConnBank.Open();
    OleAda.Fill(oDs);
    ConnBank.Close();
    return oDs;
    }
    //購物
    public void Buy(string sCardNO , ArrayList Arr)
    {
    //****************構建連接******************
    string sConnShop = "Provider=sqloledb;Data Source=JANE;Initial Catalog=Shop;User Id=sa;";
    string sConnBank = "Provider=sqloledb;Data Source=JANE;Initial Catalog=Bank;User Id=sa;";
    OleDbConnection ConnShop = new OleDbConnection(sConnShop);
    OleDbConnection ConnBank = new OleDbConnection(sConnBank);
    OleDbCommand CmdShop = new OleDbCommand();
    CmdShop.Connection = ConnShop;
    OleDbCommand CmdBank = new OleDbCommand();
    CmdBank.Connection = ConnBank;
    try
    {
    //****************打開連接*******************
    ConnBank.Open();
    ConnShop.Open();
    //******************************************
    if(!ContextUtil.IsInTransaction)
    {
    throw new Exception("Not in trsaction!");
    }
    //************操作資料庫Shop******************
    int nCost = 0 ;
    for(int i = 0 ; i < Arr.Count ; i++)
    {
    Item item = (Item)Arr[i];
    string sWareNO = item.sNO;
    int nCount = item.nCount;
    ReduceShopStock(sWareNO,nCount,CmdShop);
    nCost += nCount;
    }
    //************操作資料庫Bank******************
    ReduceCreditAmount(sCardNO , nCost , CmdBank);
    //*******************提交********************
    ContextUtil.SetComplete();
    }
    catch(Exception Ex)
    {
    //****************回滾************************
    ContextUtil.SetAbort();
    throw new Exception(Ex.Message);
    }
    finally
    {
    ConnBank.Close();
    ConnShop.Close();
    }
    }
    //減少庫存
    public void ReduceShopStock(string sWareNO , int nCount , OleDbCommand cmd)
    {
    string sCmd = "SELECT NUM FROM WARE WHERE WARENO ='" + sWareNO + "'";
    OleDbDataAdapter ada= new OleDbDataAdapter(sCmd , cmd.Connection);
    DataSet oDs = new DataSet();
    ada.Fill(oDs);
    int nStock = 0 ;
    if(oDs.Tables[0].Rows.Count > 0)
    {
    nStock = int.Parse(oDs.Tables[0].Rows[0][0].ToString().Trim());
    }
    if(nCount > nStock)
    {
    throw new Exception(sWareNO + " didn't have enough stock[" + nStock +"]");
    }
    sCmd = "UPDATE WARE SET NUM =" + Convert.ToString(nStock - nCount) + " WHERE WARENO ='" + sWareNO + "'";
    cmd.CommandText = sCmd;
    if(cmd.ExecuteNonQuery()<=0)
    {
    throw new Exception("Can not found [" + sWareNO + "]");
    }
    }
    //減少金額
    public void ReduceCreditAmount(string sCardNO , int nCost , OleDbCommand cmd)
    {
    string sCmd = "SELECT AMOUNT FROM CREDIT_INFO WHERE CREDIT_NO ='" + sCardNO + "'";
    OleDbDataAdapter ada = new OleDbDataAdapter(sCmd , cmd.Connection);
    DataSet oDs = new DataSet();
    ada.Fill(oDs);
    int nAmount = 0;
    if(oDs.Tables[0].Rows.Count > 0)
    {
    nAmount = int.Parse(oDs.Tables[0].Rows[0][0].ToString().Trim());
    }
    if(nAmount < nCost)
    {
    throw new Exception("Sorry! You don't have enough money!");
    }
    sCmd = "UPDATE CREDIT_INFO SET AMOUNT = " + Convert.ToString(nAmount - nCost) + " WHERE  CREDIT_NO ='" + sCardNO + "'";
    cmd.CommandText  = sCmd;
    if(cmd.ExecuteNonQuery()<=0)
    {
    throw new Exception("Can not found [" + sCardNO +"]");
    }
    }
    }
    }
      

  4.   

    using System;namespace ItemInfo
    {
    /// <summary>
    /// Class1 的摘要描述。
    /// </summary>
    [Serializable]
    public class Item
    {
    public Item()
    {
    }
    public string sNO;
    public int nCount;
    }
    }
      

  5.   

    太長了,需要的話和我聯繫,我建議csdn允許上傳文件
    [email protected]
      

  6.   

    .net 本来就是可以很好地实现与com+的结合