2009-10-14 6 views
8

トランザクションとmsdtcがどのように連携するかについて基本的な混乱があります。トランザクションとmsdtcに関する混乱

私は基本的なサーバー/クライアントwinformsアプリケーションを持っています。このアプリは、transactionscopeを使用して、SQL Server上で実行されるいくつかのSQLコマンドをカプセル化します。

サーバ上でmsdtcネットワークアクセスを有効にしたときにアプリが正常に動作しているように見えました。その後、ある日、ネットワークアクセスが有効になっていないとのことが止まった。

今、トランザクションスコープを動作させるために、クライアントコンピュータとサーバーの両方でmsdtcネットワークアクセスを有効にする必要があるようです。

クライアントまたはサーバーのmsdtcサービスがトランザクション処理を実行しますか。あるいはその両方?

msdtcネットワークへのアクセスがクライアントとサーバーの両方で必要となるかどうかについての指導はありますか?

答えて

10

MSDTCを使用している場合は、クライアント(アプリケーション)とサーバー(データベース)がMSDTCを実行し、正しく構成されている必要があります。

これは、特にファイアウォールを扱うときの痛みの原因となります。問題がある場合はTroubleshooting Problems with MSDTCを参照してください。 BizTalkについて語っていますが、一般的にはMSDTCに適用されます。 DTCPINGもあなたの友人です。

SQL Server 2005以降を使用していて、1つのデータベースのみにアクセスし、1つのデータベース接続を使用しており、アプリケーションドメイン間でトランザクションを渡していない場合は、MSDTCを使用する必要はありません。このような状況では、System.Transactionsトランザクションマネージャーがトランザクションを管理します。以前の状況が発生した場合、トランザクションは分散トランザクションに昇格されます(トランザクションマネージャはMSDTCになります)。詳細は、Transaction Management Escalationを参照してください。

一般的に、MSDTCを使用しない場合は、使用しないことをお勧めします。つまり、SQL Server 2005以降のデータベースを1つしか扱っていない場合は、MSDTCを使用しないようにコードを設計してください。 MSDTCへのすべての呼び出しが2フェーズコミットプロトコル(MSDTCが使用する)のオーバーヘッドと組み合わされてプロセス外になっているため、構成の手間に加えて、DTCはパフォーマンス上のペナルティを課します。

あなたの特定の状況で何が起こっているのかについては、言い難いです。コードが変更されていない場合は、ファイアウォールのルールが変更されている可能性があります。私はまた、Windowsのアップデートが問題を引き起こしたDTC設定(セキュリティ用)を変更するのを見た。コメントに基づいて

更新:

取引プロモーションやエスカレーションを監視するため、私はあなたがコミットされたトランザクションを追跡するために、分散トランザクションコーディネータのパフォーマンスカウンタの一部を使用できると思い任意の分散トランザクションを使用していない場合。テストの場合、MSDTCを無効にしてコードが失敗するかどうかを確認できます。別の方法は、SQL Serverでトランザクションを監視することです。コーディングの観点から、DistributedTransactionStartedイベントを処理し、いくつかのロギングを実行することができます(ただし、運用に入る前にそのコードを削除してください)。

単一接続を使用するコード例については、MSDNのTransactionScopeページを参照してください。基本的には、TransactionScopeを作成し、SqlConnectionを作成し、SqlConnectionでいくつかの作業を行い、接続を閉じてscope.Complete()を呼び出します。

データアダプタメソッドを使用している場合、接続が自動的に管理され、接続が閉じられたり接続プールに返されることに注意してください。いずれにしても、別の操作が呼び出されると、トランザクションはDTCトランザクションに昇格されます。詳細については、System.Transactions and connection poolingを参照してください。ここでは、Tuzoの説明@に拡大すること

+0

感謝を。私はMSDTCを使用したくないです。私はsql2005、1 dbを使用して、アプリのドメインを渡さないが、私は1つの接続を使用している場合はわからない。 dtcに昇格しない複数のSQL文を使用したトランザクションの簡単な例を挙げることはできますか? トランザクションがmsdtcに昇格されているかどうかを知るツールや他の方法はありますか? – muhan

7

は常にエスカレートするコマンドの例です。実際には

using(var scope = new TransactionScope()) 
{ 
    using(var conn = new SqlConnection(connString)){ 
    conn.Open(); 
    //...some command, etc. 
    } 
    using(var conn = new SqlConnection(connString)){ 
    conn.Open(); 
    //...some command, etc. 
    } 
    scope.Complete(); 
} 

を、接続とコマンドが別のクラスになります、など、あなたが得ますアイディア。接続文字列が同じデータベースであっても、2つの接続であるため、DTCを使用して接続文字列をエスカレートします。非エスカレートトランザクションは次のようになります。これは、より良いコードは、とにかくある

using(var scope = new TransactionScope()) 
{ 
    using(var conn = new SqlConnection(connString)){ 
    conn.Open(); 
    //...some command, etc. 
    //...some other command, etc. 
    } 
    scope.Complete(); 
} 

あなたが接続を開くために、あなたが必要なものを行うには、できるだけ早く閉じます。これは、接続管理を通して考える必要があることを意味します。あなたのアプリに応じて、これを別の方法で実装することができます。例:

using(var scope = new TransactionScope()) 
using(var conn = new SqlConnection(connString)) 
{ 
    conn.Open(); 
    var myService = new MyService(conn); 
    var myService2 = new MyService2(conn); 
    myService.DoSomething(); 
    myService2.DoSomething(); 
    scope.Complete(); 
} 

これを実装する方法はさまざまです。エンタープライズライブラリのデータアクセスアプリケーションブロック、およびさまざまなORMは、接続やトランザクションをより効率的に処理するのに役立ちます。

+1

エンタープライズライブラリのデータアクセスブロックは、アクティブなトランザクションとその接続の内部リスト(TransactionScopeConnectionsクラス内)を維持するため役立ちます。同じ接続がトランザクションの存続期間中に使用されるため、トランザクションは分散トランザクションにエスカレートしません。また、データベース接続を使用する必要のあるすべてのメソッドに接続を渡す必要がないため、インターフェイスをよりクリーンにするという利点もあります。 –

+1

SQLserver 2008のユーザーの場合:コードの最初の例はSQLserver 2008ではエスカレートされません。最初の接続を閉じる前に最初の接続を終了しないとエスカレートしません(たとえば、ステートメント)。 – mipe34

0

更新:GetDataとUpdateの両方を、TransactionScope内の同じデータアダプタでのみ回避策と共に使用するときに、トランザクションがLTMからMSDTCに昇格される理由を説明する記事が見つかりました。

決定的TableAdapters +トランザクションのブログ記事 http://blah.winsmarts.com/2006/06/18/the-definitive-tableadapters--transactions-blog-post.aspx

私はかつて、分散されるトランザクションをエスカレートで開いた複数の接続を持っていることについての部分を理解しています。ただし、接続が1つしかなく、エスカレートしているデータベースに対して1つのクエリが発生するという問題があります。ストアドプロシージャにもトランザクションはありません。誰かが手がかりを持っているなら、私はそれを聞きたい。私のコード例から、 "adapter.Update(table)"は分散トランザクションをトリガーします。

私は既存のプロジェクトからコードを取り除き、何が起こっているのかを単純化しました。私はまだ同じ問題を抱えています。これは、基本的にテーブルアダプタを使用してデータセットを作成し、それをストアドプロシージャで設定して選択、挿入、および削除することです。私は、特定のユーザーと関連するすべてのレコードを選択します。次に、レコードのいずれかに「myPPID」が存在するかどうかによって、レコードを追加または削除します。次に、更新メソッドを呼び出して、コンポーネントサービスのトランザクション統計を見て、トランザクションのエスカレートが配信されることを確認します。

私はWindows XP Pro SP3と.NET Framework 3.5をクライアントプログラムに使用しています。 LANを介してWindows Server 2003 R2 Enterprise Edition SP2に接続するSQL 2005データベースに接続します。

private void button1_Click(object sender, EventArgs e) 
{ 
int userId = 3; 
int myPPId = 881; 
using (TransactionScope ts = new TransactionScope()) 
{ 
    using (DataSet1TableAdapters.AssignedPPTableAdapter adapter 
    = new MSDTCPromotionTest.DataSet1TableAdapters.AssignedPPTableAdapter()) 
    { 
     using (DataSet1.AssignedPPDataTable table = adapter.GetData(userId)) 
     { 
      DataSet1.AssignedPPRow row = table.FindByUserIdmyPPId(
       userId, myPPId); 
      if (row == null) 
      { 
       table.AddAssignedPPRow(userId, myPPId, string.Empty, 
        string.Empty, true); 
      } 
      else 
      { 
       row.Delete(); 
      } 
      adapter.Update(table); 
     } 
     ts.Complete(); 
    } 
} 
} 

接続文字列は特別なものではありません。また

<add name="ConnectionString" connectionString=" 
Data Source=devdb; 
Initial Catalog=&quot;TEST MSDTC&quot;; 
Integrated Security=True" 
providerName="System.Data.SqlClient" /> 

、ストアドプロシージャは、単純なCRUDの呼び出しです。

登録:

ALTER procedure [dbo].[p_UserForm_AssignedPP_Insert] 
(
    @UserId INT, 
    @myPPId int 
) 
AS 
SET NOCOUNT ON; 
INSERT INTO [UsermyPP] ([UserID],[myPPID],[DateCreated]) 
    VALUES (@UserId,@myPPId,GETutcDATE()) 

読む:

ALTER procedure [dbo].[p_UserForm_AssignedPP_SelectByUserId] 
(
    @UserId int 
) 
AS 
SELECT 
    [UserId], 
    [myPPId], 
    '' Title, 
    '' Abbreviation, 
    0 IsArchived 
from 
    UsermyPP unpp 
where 
    unpp.[userid] = @UserId 

を削除します。偉大な情報のため

ALTER procedure [dbo].[p_UserForm_AssignedPP_Delete] 
(
    @Original_UserId INT, 
    @Original_MyPPId INT 
) 
AS 
SET NOCOUNT ON; 
DELETE FROM usermypp WHERE [UserID] = @Original_UserId 
    AND [MyPPID] = @Original_MyPPId 
関連する問題