4

同じSQLServer上の2つの異なるデータベースにいくつかのトランザクションをラップするのに苦労しています。最初はネットワークDTCアクセスに問題があり、それを解決しました。現在、引き続き発生するエラーは、「基になるトランザクションマネージャーとの通信に失敗しました」です。

データベースにいくつかの顧客プロファイルがあり、これらのプロファイルが古くなった場合は、それらを「アーカイブ」データベースに移動して保存します。移動は、単に(ユーモアのイタリック体)アーカイブデータベースにそれらを追加し、メイン/ライブデータベースからそれらを削除することです。データベースごとにDataContextがあります。以下のコードは、追加を実行し、2番目のDataContextを使用しようとすると、削除でエラーが発生します。LINQを使用してから数か月しか経っていませんが、過去2日間は記事を精査してきました。コードに問題があるかどうか、またはDTCまたは???で正しく構成されていないものがあるかどうかを知りたいのですが。

ワークステーションとサーバーをVMwareで実行しています。-ワークステーションはWindows7SP1-サーバーはWindowsおよびSQLServer2008R2

「移動」のルーチン:

private int MoveProfileToArchiveDB( int iProfileId )
{
    int rc = RC.UnknownError;

    // get new Archive profile object
    ProfileArchive.ProfileInfo piArchive = new ProfileArchive.ProfileInfo();

    // 'Live' DataContext
    using ( ProfileDataContext dbLive = new ProfileDataContext() )
    {
        // get Live profile
        ProfileInfo piLive = ProfileInfo.GetProfile( dbLive, iProfileId );

        // copy Live data to Archive profile object... including the id
        ProfileArchive.ProfileInfo.CopyFromLive( piLive, piArchive, true );
    }

    bool bArchiveProfileExists = ProfileArchive.ProfileInfo.ProfileExists( piArchive.id );

    // make the move a transaction... 
    using ( TransactionScope ts = new TransactionScope() )
    {
        // Add/Update to Archive db
        using ( ProfileArchiveDataContext dbArchive = new ProfileArchiveDataContext() )
        {
            // if this profile already exists in the Archive db...
            if ( bArchiveProfileExists )
            {
                // update the personal profile in Archive db
                rc = ProfileArchive.ProfileInfo.UpdateProfile( dbArchive, piArchive );
            }
            else
            {
                // add this personal profile to the archive db
                int iArchiveId = 0;
                piArchive.ArchiveDate = DateTime.Now;
                rc = ProfileArchive.ProfileInfo.AddProfile( dbArchive, piArchive, ref iArchiveId );
            }

            // if Add/Update was successful...
            if ( rc == RC.Success )
            {
                // Delete from the Live db
                using ( ProfileDataContext dbLive = new ProfileDataContext() )
                {
                    // delete the personal profile from the Profile DB
                    rc = ProfileInfo.DeleteProfileExecCmd( dbLive, iProfileId );    // *** ERROR HERE ***
                    if ( rc == RC.Success )
                    {
                        // Transaction End (completed)
                        ts.Complete();
                    }
                }
            }
        }

    }

    return rc;
}

ノート:

  1. Deleteにはいくつかの異なるメソッドがあり、それらはすべてTransactionScopeの外部で機能します。
  2. ProfileInfoはメインのプロファイルテーブルであり、ライブデータベースとアーカイブデータベースの両方でほぼ同じです。

どんな助けでも大歓迎です!どうもありがとう...

4

1 に答える 1

8

十字架のコメントを続けるのではなく、代わりにこれを回答として投稿することにしました。

  • エラーコードは使用しないでください。それが例外です。コードフローは読みにくく、エラーコードは無視されるように招待を返します。例外により、コードが読みやすくなり、エラーが発生しにくくなります。

  • TransactionScopeを使用する場合は、常に分離レベルを明示的に設定することを忘れないでください。有害と考えられる新しいTransactionScope()の使用を参照してください。SERIALIZABLEの暗黙的な分離レベルが要求されることはほとんどなく、スケールに多大な悪影響を及ぼします。

  • トランザクションのエスカレーション。トランザクションスコープ内で複数の接続が開かれると、トランザクションを分散トランザクションにエスカレートできます。動作はバージョンごとに異なり、一部の人はそれを文書化しようとしました。TransactionScope:トランザクションエスカレーション動作

SQL Server 2008は、SQL Server 2005よりもはるかにインテリジェントであり、特定のトランザクション内のすべてのデータベース接続が同じ物理データベースを指しているかどうかを自動的に検出できます。この場合、トランザクションはローカルトランザクションのままであり、分散トランザクションにエスカレーションされません。残念ながら、いくつかの注意点があります。

  • 開いているデータベース接続がネストされている場合でも、トランザクションは分散トランザクションにエスカレートされます。
  • トランザクションで別の永続リソースへの接続が確立された場合、トランザクションはすぐに分散トランザクションにエスカレートされます。

(使用される2つのデータコンテキストからの)接続は異なるデータベースを指しているため、SQL Server 2008でも、TransactionScopeは分散トランザクションにエスカレートします。

アプリケーションをDTCに参加させることは、少なくとも2つの点で有害です。

  • スループットはフロア全体に低下します。データベースは1秒あたり数千のローカルトランザクションをサポートできますが、1秒あたりの分散トランザクションは数十(おそらく数百)にすぎません。これは主に、2フェーズコミットの複雑さによるものです。
  • DTCにはコーディネーターMSDTCが必要です。[MSDTCに加えられたセキュリティ強化]は構成をより困難にし、開発者がアプリにMSDTCが必要であることを発見することは確かに予想外です。リンクされた記事で説明されている手順は、おそらく現在あなたが見逃しているものです。Windows Vista / Windows 7 / Windows Server 2008 / Windows Server 2008R2の場合、手順は、WindowsVistaおよびWindowsServer 2008のMSDTC、Windows2008でDTCの構成方法およびその他の同様の記事で説明されています。

上記の記事に従ってMSDTC通信を修正すると、コードは機能するはずですが、EFを実行しているクライアントコードではこのアーカイブは発生しないはずです。はるかに優れたツールがあり、SSISがその代表的な例です。SSISを実行する夜間にスケジュールされたジョブは、これらの未使用のプロファイルをはるかに効率的に転送します。

于 2012-06-27T20:22:54.223 に答える