天天看點

SQL2K,DTC錯誤:"該夥伴事務管理器已經禁止了它對遠端/網絡事務的支援"的解決辦法

近日在用wf做資料持久化時發現:該夥伴事務管理器已經禁止了它對遠端/網絡事務的支援。 (異常來自 HRESULT:0x8004D025)的錯誤。

我是通過網絡通路同僚的sqlserver2000 時出現如上錯誤的,并且發生不能進行資料的持久化,找了些資料,發現是這個問題,換成本地sql就可以了。

還是貼一下問題的原因和解決辦法:

在分布式應用程式中,不可避免地會經常使用到事務控制。事務有一個開頭和一個結尾,它們指定了事務的邊界,事務在其邊界之内可以跨越程序和計算機。事務邊界内的所有資源都參與同一個事務。要維護事務邊界内資源間的一緻性,事務必須具備 ACID 屬性,即原子性、一緻性、隔離性和持續性。

1.本地事務和分布式事務

  本地事務是其範圍為單個可識别事務的資料資源的事務(例如,Microsoft SQL Server 資料庫或 MSMQ 消息隊列)。例如,當單個資料庫系統擁有事務中涉及的所有資料時,就可以遵循 ACID 規則。在 SQL Server 的情況下,由内部事務管理器來實作事務的送出和復原操作。

  分布式事務可以跨越不同種類的可識别事務的資料資源,并且可以包括多種操作(例如,從 SQL 資料庫檢索資料、從 Message Queue Server 讀取消息以及向其他資料庫進行寫入)。通過利用跨若幹個資料資源來協調送出和中止操作以及恢複的軟體,可以簡化分布式事務的程式設計。Microsoft Distributed Transaction Coordinator (DTC) 就是一種這樣的技術。它采用一個二階段的送出協定,該協定可確定事務結果在事務中涉及的所有資料資源之間保持一緻。DTC 隻支援已實作了用于事務管理的相容接口的應用程式。這些應用程式被稱為資料總管(有關此主題的詳細資訊,請參見 .NET Framework Developer's Guide 中的 Distributed Transactions <http://msdn.microsoft.com/library/en-us/cpguide/html/cpconDistributedTransactions.asp>; ),目前存在許多這樣的應用程式,包括 MSMQ、Microsoft SQL Server、Oracle、Sybase 等等。

2.資料庫事務

如果調用一個在 BEGIN TRANSACTION 和 COMMIT/ROLLBACK TRANSACTION 語句中封裝了所需操作的存儲過程,您就可以在到資料庫伺服器的單個往返行程中運作事務,進而實作最佳性能。資料庫事務還支援嵌套事務,這意味着您可以從一個活動事務中啟動一個新事務。在下面的代碼片斷中,BEGIN TRANSACTION 語句開始了一個新事務。可以通過使用 COMMIT TRANSACTION 語句将更改送出到資料庫來結束事務,或者,在發生任何錯誤的情況下,通過使用 ROLLBACK TRANSACTION 語句将所有更改撤消來結束事務:

CREATE PROCEDURE dbo.SPTransaction

    (

    @UpdateID int,

    @UpdateValue nchar(50),

    @InsertID int,

    @InsertValue nchar(50)

    )

AS

begin Tran

Update Region  Set RegionDescription=@UpdateValue where RegionID=@UpdateID

insert into Region Values (@InsertID,@InsertValue)

declare @RegionError int

select @RegionError=@@error

if(@RegionError=0)

COMMIT Tran

else

ROLLBACK Tran

GO

** /// /  <summary>

         ///  SQL事務:

         ///   </summary>

         public   void  SQLTran()

        {

            SqlConnection conn  =   new  SqlConnection( " Data Source=127.0.0.1;Initial Catalog=Northwind;Persist Security Info=True;User ID=sa;Password=123; " );

            SqlCommand cmd  =   new  SqlCommand();

            cmd.CommandText  =   " SPTransaction " ;

            cmd.CommandType  =  CommandType.StoredProcedure;

            cmd.Connection  =  conn;

            conn.Open();

            SqlParameter[] paras =   new  SqlParameter[]{

              new  SqlParameter ( " @UpdateID " ,SqlDbType.Int, 32 ),

              new  SqlParameter ( " @UpdateValue " ,SqlDbType .NChar, 50 ),

              new  SqlParameter ( " @InsertID " ,SqlDbType.Int , 32 ),

             new  SqlParameter ( " @InsertValue " ,SqlDbType.NChar , 50 )};

            paras[ 0 ].Value  =   " 2 " ;

            paras[ 1 ].Value  =   " Update Value1 " ;

            paras[ 2 ].Value  =   " 6 " ;

            paras[ 3 ].Value  =   " Insert Value1 " ;

             foreach  (SqlParameter para  in  paras )

            {

                cmd.Parameters.Add(para);

            }

            cmd.ExecuteNonQuery();   

        }

3.手動事務

利用手動事務,您可以使用開始和結束事務的顯式指令來顯式控制事務邊界。此模式還支援允許您從活動事務中開始一個新事務的嵌套事務。但是,應用此控制會給您增加一種額外負擔,您需要向事務邊界登記資料資源并對這些資源進行協調。由于對分布式事務沒有任何内置的支援,是以,如果您選擇以手動方式來控制分布式事務,将承擔許多責任;您需要控制每個連接配接和資源登記,并通過提供實作來保持事務的 ACID 屬性。  

ADO.NET 手動事務  

這兩種 Microsoft ADO.NET 資料提供程式通過提供建立到資料存儲區的連接配接、開始一個事務、送出或中止事務以及最後關閉連接配接的一組對象來啟用手動事務。我們将以 ADO.NET SQL 托管提供程式為例來進行說明。要在單個事務中執行操作,您需要建立 SQLTransaction 對象、使用 SQLConnection 對象開始事務、確定在事務内進行資料庫互動以及送出或中止事務。SQLTransaction 對象提供了多種方法和屬性來控制事務。如果事務中的每個操作都已經成功完成,可以使用 “送出” 方法将所做的更改送出到資料庫。使用 SQLTransaction 對象的 “復原” 方法可以復原更改。注意 "指令" 對象的 Transaction 屬性必須設定為一個已經開始的事務,這樣,它才能在該事務中執行。

SQLConnection Conn  =  New SQLConnection( " ConnString " ); 

SQLCommand Cmd  =  New SQLCommand; 

//  Open a connection 

Conn.Open(); 

//  Begin a transaction 

SQLTransaction Txn  =  Conn.BeginTransaction();

//  Set the Transaction in which the command executes 

Cmd.Transaction  =  Txn; 

MSMQ 手動事務  

.NET Framework 以兩種不同的方式支援 MSMQ 事務:通過允許多個消息作為事務的一部分發送或接收而手動(内部)支援;通過參與 Distributed Transaction Coordinator (DTC) 事務而自動(外部)支援。MSMQ 手動事務是通過 MessageQueueTransaction 類來支援的,并且完全在 MSMQ 引擎内處理。有關詳細資訊,請參見 Duncan Mackenzie 的文章 Reliable Messaging with MSMQ and .NET <http://msdn.microsoft.com/library/en-us/dnbda/html/bdadotnetasync2.asp>;

4.自動事務

.NET Framework 依靠 MTS/COM+ 服務來支援自動事務。COM+ 使用 Microsoft Distributed Transaction Coordinator (DTC) 作為事務管理器和事務協調器在分布式環境中運作事務。這樣可使 .NET 應用程式運作跨多個資源結合不同操作(例如,将定單插入 SQL Server 資料庫、将消息寫入 Microsoft 消息隊列 (MSMQ) 隊列、發送電子郵件以及從 Oracle 資料庫檢索資料)的事務。 通過提供基于聲明性事務的程式設計模型,COM+ 使應用程式可以很容易地運作跨不同種類的資源的事務。這種做法的缺點是,由于存在 DTC 和 COM 互操作性開銷,導緻性能降低,而且不支援嵌套事務。

ASP.NET 頁、Web Service 方法和 .NET 類通過設定聲明性事務屬性都可以标記為事務性。  

a.ASP.NET: <@ Page Transaction="Required">

b.ASP.NET Web 服務

<%@ WebService Language="VB" Class="Class1" %>

<%@ assembly name="System.EnterpriseServices" %>

Public Class Class1 Inherits WebService

<WebMethod(TransactionOption := TransactionOption.RequiresNew)> _

Public Function Method1()

… 

c.要參與自動事務,.NET 類必須是從 System.EnterpriseServices.ServicedComponent 類繼承的,這可使得該 .NET 類能夠在 COM+ 内運作。在這個過程中,要将 COM+ 與 DTC 進行互動以建立一個分布式事務,也要登記背景的所有資源連接配接。您還需要對該類設定聲明性事務屬性以确定其事務性行為。

[Transaction(TransactionOption.Required)] 

public   class  Class1 : ServicedComponent { 

// … 

類的事務屬性可以設定為以下任何選項:

• “禁用”

— 訓示該對象從不在 COM+ 事務中建立。該對象可以直接使用 DTC 來獲得事務性支援。

• NotSupported

— 訓示該對象從不在事務中建立。

• “支援”

— 訓示該對象在其建立者的事務的上下文中運作。如果該對象本身是根對象,或者其建立者不在事務中運作,則該對象将在不使用事務的情況下建立。

• “必選”

— 訓示對象在其建立者的事務的上下文中運作。如果該對象本身是根對象,或者其建立者不在事務中運作,則該對象将使用一個新事務來建立。

• RequiresNew

— 訓示該對象需要一個事務,并且該對象使用新事務來建立。  

下面的代碼顯示了配置為在 COM+ 中運作、将程式集屬性設定為配置 COM+ 應用程式屬性的 .NET 類。

using  System;

using  System.Runtime.CompilerServices; 

using  System.EnterpriseServices;

using  System.Reflection; 

// Registration details. 

// COM+ application name as it appears in the COM+ catalog 

[Assembly: ApplicationName( " Class1 " )] 

' Strong name for assembly 

[Assembly: AssemblyKeyFileAttribute( " class1.snk " )] 

[Assembly: ApplicationActivation(ActivationOption.Server)] 

[Transaction(TransactionOption.Required)] 

public   class  Class1 : ServicedComponent { 

[AutoComplete] 

public   void  Example1() 

// … 

指定要安裝該程式集的元件的 COM+ 應用程式的名稱。 指定 COM+ 應用程式是否為伺服器應用程式或庫應用程式。指定 ApplicationActivation(ActivationOption.Server)時,必須使用 gacutil 指令行工具 (GacUtil.exe) 将程式集安裝到全局程式集緩存 (GAC)。  

您可以使用 Regsvcs.exe 指令行工具将程式集轉換為類型庫,并将類型庫注冊和安裝到指定的 COM+ 應用程式中。該工具還可用來配置您已經用程式設計方式添加到程式集中的屬性。例如,如果在程式集中指定 ApplicationActivation(ActivationOption.Server),該工具将建立一個伺服器應用程式。如果在未使用 COM+ 來安裝程式集的情況下調用程式集,運作時将建立和注冊一個類型庫,并使用 COM+ 來安裝該庫。您可以在元件服務管理單元中看到和配置為程式集建立的 COM+ 應用程式。  

通過使用System.EnterpriseServices.ContextUtil 類,可以獲得有關 COM+ 對象上下文的資訊。它提供SetComplete 和 SetAbort 方法,以便分别顯式送出和復原事務。正如您預想的那樣,當所有操作已成功執行後,緊随 try 程式塊的最後調用 ContextUtil.SetComplete 方法來送出事務。所引發的任何異常将在 catch 程式塊中被捕獲,該程式塊使用ContextUtil.SetAbort 中止事務。 

您還可以使用System.EnterpriseServices.AutoComplete 屬性類來讓服務元件自動選擇是送出事務還是中止事務。如果方法調用成功傳回,元件将傾向于選擇送出事務。如果方法調用引發異常,事務會自動中止;您無需顯式調用 ContextUtilSetAbort。要使用此功能,應在類方法之前插入 <AutoComplete> 屬性:

[Transaction(TransactionOption.Required)] 

public   class  Class1 : ServicedComponent { 

[AutoComplete] 

public   void  Example1() 

// … 

在需要事務跨 MSMQ 和其他可識别事務的資源(例如,SQL Server 資料庫)運作的系統中,隻能使用 DTC 或 COM+ 事務,除此之外沒有其他選擇。DTC 協調參與分布式事務的所有資料總管,也管理與事務相關的操作。

5 TransactionScope事務

  TransactionScope事務類,它可以使代碼塊成為事務性代碼。并自動提升為分布式事務

 優點:實作簡單,同時能夠自動提升為分布式事務

** /// /  <summary>

         ///  TransactionScope事務:可自動提升事務為完全分布式事務的輕型(本地)事務。 

         ///  使用時要保證MSDTC服務(控制分布事務)是開啟的可以使用:net start msdtc指令開啟服務;

         ///   </summary>

         public   void  ADONetTran2()

        {

             SqlConnection conn  =   new  SqlConnection( " Data Source=127.0.0.1;Initial Catalog=Northwind;Persist Security Info=True;User ID=sa;Password=123; " );

             SqlCommand cmd  =   new  SqlCommand();

             try

            {

                 using  (System.Transactions.TransactionScope ts  =   new  TransactionScope())

                {

                    cmd.CommandText  =   " Update Region Set [email protected] where [email protected] " ;

                    cmd.CommandType  =  CommandType.Text;

                    cmd.Connection  =  conn;

                    conn.Open();

                    SqlParameter[] paras  =   new  SqlParameter[]{

                                         new  SqlParameter ( " @UpdateID " ,SqlDbType.Int, 32 ),

                                         new  SqlParameter ( " @UpdateValue " ,SqlDbType .NChar, 50 )};

                    paras[ 0 ].Value  =   " 2 " ;

                    paras[ 1 ].Value  =   " Update Value12 " ;

                     foreach  (SqlParameter para  in  paras)

                    {

                        cmd.Parameters.Add(para);

                    }

                    cmd.ExecuteNonQuery();

                    cmd.CommandText  =   " insert into Region values(@InsertID,@InsertValue) " ;

                    cmd.CommandType  =  CommandType.Text;

                    paras  =   new  SqlParameter[]{

                                         new  SqlParameter ( " @InsertID " ,SqlDbType.Int , 32 ),

                                         new  SqlParameter ( " @InsertValue " ,SqlDbType.NChar , 50 )};

                    paras[ 0 ].Value  =   " 8 " ;

                    paras[ 1 ].Value  =   " Insert Value " ;

                    cmd.Parameters.Clear();

                     foreach  (SqlParameter para  in  paras)

                    {

                        cmd.Parameters.Add(para);

                    }

                    cmd.ExecuteNonQuery();

                     // 送出事務

                    ts.Complete();

                }

            }

             catch

            {

                 throw ;

            }

             finally

            {

                conn.Close();

            }

        }

4 COM+事務

  在分布式應用程式中,往往要同時操作多個資料庫,使用資料庫事務就不能滿足業務的要求了。在COM+中,提供完整的事務處理服務。很友善處理多個資料庫上的事務。

///   <summary>

         ///  COM+事務

         ///   </summary>

         public   void  ComTran()

        {

            SqlConnection conn  =   new  SqlConnection( " Data Source=127.0.0.1;Initial Catalog=Northwind;Persist Security Info=True;User ID=sa;Password=123; " );

            SqlCommand cmd  =   new  SqlCommand();

            ServiceConfig sc  =   new  ServiceConfig();

             // 指定事務類型

            sc.Transaction  =  TransactionOption.Required;

             // 設定啟動跟蹤

            sc.TrackingEnabled  =   true ;

             // 建立一個上下文,該上下文的配置由作為 cfg 參數傳遞的 ServiceConfig 對象來指定。

             // 随後,用戶端和伺服器端的政策均被觸發,如同發生了一個方法調用。

             // 接着,新的上下文被推至上下文堆棧,成為目前上下文

            ServiceDomain.Enter(sc);

             try

            {

                    cmd.CommandText  =   " Update Region Set [email protected] where [email protected] " ;

                    cmd.CommandType  =  CommandType.Text;

                    cmd.Connection  =  conn;

                    conn.Open();

                    SqlParameter[] paras  =   new  SqlParameter[]{

                                         new  SqlParameter ( " @UpdateID " ,SqlDbType.Int, 32 ),

                                         new  SqlParameter ( " @UpdateValue " ,SqlDbType .NChar, 50 )};

                    paras[ 0 ].Value  =   " 2 " ;

                    paras[ 1 ].Value  =   " Update Value22 " ;

                     foreach  (SqlParameter para  in  paras)

                    {

                        cmd.Parameters.Add(para);

                    }

                    cmd.ExecuteNonQuery();

                    cmd.CommandText  =   " insert into Region values(@InsertID,@InsertValue) " ;

                    cmd.CommandType  =  CommandType.Text;

                    paras  =   new  SqlParameter[]{

                                         new  SqlParameter ( " @InsertID " ,SqlDbType.Int , 32 ),

                                         new  SqlParameter ( " @InsertValue " ,SqlDbType.NChar , 50 )};

                    paras[ 0 ].Value  =   " 9 " ;

                    paras[ 1 ].Value  =   " Insert Value " ;

                    cmd.Parameters.Clear();

                     foreach  (SqlParameter para  in  paras)

                    {

                        cmd.Parameters.Add(para);

                    }

                    cmd.ExecuteNonQuery();

                     // 送出事務

                    ContextUtil.SetComplete();

            }

             catch

            {

                 // 復原事務

                ContextUtil.SetAbort();

                 throw ;

            }

             finally

            {

                conn.Close();

                 // 觸發伺服器端的政策,随後觸發用戶端的政策,如同一個方法調用正在傳回。

                 // 然後,目前上下文被彈出上下文堆棧,調用 Enter 時正在運作的上下文成為目前的上下文。

                ServiceDomain.Leave();

            }

        }

需要特别補充的是:

如果你使用的是分布事務(TransactionScope事務和COM+事務),在預設情況下你是要重新配置安裝SQL Server資料庫伺服器和通路資料庫的用戶端的.(如果沒有配置運作會出現以下錯誤:該夥伴事務管理器已經禁止了它對遠端/網絡事務的支援。 (異常來自 HRESULT:0x8004D025)

)下面是MSDN上關于配置分布式事務的一段原話:

配置分布式事務

要啟用分布式事務,可能需要通過網絡啟用 MS DTC,以便在使用應用了最新的 Service Pack 的較新作業系統(例如 Windows XP 或 Windows 2003)時使用分布式事務。如果啟用了 Windows 防火牆(Windows XP Service Pack 2 的預設設定),必須允許 MS DTC 服務使用網絡或打開 MS DTC 端口。

實際怎麼配置呢,經過我的實際使用:大緻如下:打開'控制台'->'管理工具'->'元件服務',點開'元件服務'->'計算機'->'我的電腦',在'我的電腦'上右擊屬性,點'MSDTC',然後點'安全性配置'。作為資料庫的伺服器的配置如下:

SQL2K,DTC錯誤:"該夥伴事務管理器已經禁止了它對遠端/網絡事務的支援"的解決辦法

1.先在程式計算機上設置MSDTC:控制台->管理工具->組件服務->我的電腦->右jiang->屬性->MSDTC->安全配置(Security   Configuration)->打開Network   DTC   Access   同時打上  

  Allow   Inbound   ,Allow   Outbound   ,No   Authentication   Required,Enable   Transaction   Internet   Protocol[TIP]   Transaction  

  2.請在遠程數據庫計算機上做1同樣的事情  

  3.雙方計算機重新啟動MSDTC  

  4.這樣就可以了  

而通路資料庫的用戶端的配置和伺服器端的稍有些差别:

SQL2K,DTC錯誤:"該夥伴事務管理器已經禁止了它對遠端/網絡事務的支援"的解決辦法

在設定完上面的還有使防火牆MS DTC 服務使用網絡或打開 MS DTC 端口:運作netsh firewall set allowedprogram %windir%/system32/msdtc.exe MSDTC enable指令就可以了

小結

------------------------------------------------------------------------------------------ 

    每一種事務方法都是應用程式性能和代碼可維護性的折衷。運作在存儲過程中實作的資料庫事務可提供最佳性能,因為它隻需要到資料庫的單個往返行程。另外,這種方法還提供了顯式控制事務邊界的靈活性。雖然它提供了良好的性能和靈活性,但您需要用 Transact SQL 來編寫代碼,這就不如用 .NET 來編寫代碼那麼簡單。

    使用 ADO.NET 事務對象的手動事務很易于編寫代碼,并實作了用顯式指令開始和結束事務以控制事務邊界的靈活性。但是,為獲得這種簡易性和靈活性,需要一些完成事務所需的到資料庫的額外往返行程,這導緻了性能降低。

    如果事務跨越多個可識别事務的管理器(可能包括 SQL Server 資料庫、MSMQ 消息隊列等等),自動事務将是唯一的選擇。這種方法大大簡化了應用程式設計,減少了編碼需求。不過,由于 COM+ 服務執行所有協調工作,可能有一些額外的開銷。