5

DALコードの多くは、トランザクションにTransactionScopeを使用しています。これはうまく機能しますが、SQLCLRプロシージャ内からこのDALコードを使用すると問題が発生します。トランザクションは、私が望まないものをMSDTCにエスカレートします。

問題は簡単に再現できます。

  1. CLRの実装

    [SqlProcedure]
    public static void ClrWithScope(string cmdText)
    {
        /* escalates to MSDTC when a transaction is already open */
        using ( var scope = new TransactionScope())
        {
            using (var connection = new SqlConnection("context connection=true;"))
            {
                connection.Open();
                using (var cmd = new SqlCommand(cmdText, connection))
                {
                    SqlContext.Pipe.ExecuteAndSend(cmd);
                }
            }
            scope.Complete();
        }
    }
    
    [SqlProcedure]
    public static void ClrWithTrans(string cmdText)
    {
        /* works as expected (without MSDTC escalation ) */
        using (var connection = new SqlConnection("context connection=true;"))
        {
            connection.Open();
            using (var tx = connection.BeginTransaction())
            {
                using (var cmd = new SqlCommand(cmdText, connection, tx))
                {
                    SqlContext.Pipe.ExecuteAndSend(cmd);
                    tx.Commit();
                }
            }
        }
    }
    

  2. CLRプロシージャの実行に使用されるSQLスクリプト

    BEGIN TRANSACTION
    
    exec dbo.ClrWithTrans "select * from sys.tables";
    exec dbo.ClrWithScope "select * from sys.tables"; /* <- DOES NOT WORK! */
    
    ROLLBACK TRANSACTION
    
  3. エラー

    Msg 6549, Level 16, State 1, Procedure ClrWithScope, Line 0
    A .NET Framework error occurred during execution of user defined routine or aggregate 'clrClrWithScope': 
    System.Transactions.TransactionAbortedException: Die Transaktion wurde abgebrochen. ---> System.Transactions.TransactionPromotionException: MSDTC on server 'BLABLA' is unavailable. ---> System.Data.SqlClient.SqlException: MSDTC on server 'BLABLA' is unavailable.
    System.Data.SqlClient.SqlException: 
       bei System.Data.SqlServer.Internal.StandardEventSink.HandleErrors()
       bei System.Data.SqlServer.Internal.ClrLevelContext.SuperiorTransaction.Promote()
    System.Transactions.TransactionPromotionException: 
       bei System.Data.SqlServer.Internal.ClrLevelContext.SuperiorTransaction.Promote()
       bei System.Transactions.TransactionStatePSPEOperation.PSPEPromote(InternalTransaction tx)
       bei System.Transactions.TransactionStateDelegatedBase.EnterState(InternalTransaction tx)
    System.Transactions.TransactionAbortedException: 
       bei System.Transactions.TransactionStateAborted.CreateAbortingClone(InternalTransaction tx)
       bei System.Transactions.DependentTransaction..ctor(IsolationLevel isoLevel, InternalTransaction internalTransaction, Boolean blocking)
       bei System.Transactions.Transaction.DependentClone(DependentCloneOption cloneOption)
       bei System.Transactions.TransactionScope.SetCurrent(Transaction newCurrent)
       bei System.Transactions.TransactionScope.PushScope()
       bei System.Transactions.TransactionScope..ctor(TransactionScopeOption scopeOption)
       bei Giag.Silo.Data.SqlClr.ClrWithScope(String cmdText)
    . User transaction, if any, will be rolled back.
    

「BEGINTRANSACTION」ステートメントがなくても、dbo.ClrWithScope呼び出しは正常に機能します。SQLServerによって開始されたトランザクションは、.NetFrameworkに参加している間は考慮されないと思います。

これを回避するための解決策はありますか?手動でSqlTransactionを作成し、このトランザクションを使用するようにTransactionScopeを作成するというアイデアがありますが、これを行う方法がわかりません。もう1つの解決策は、すべてのDALコードで特別なケースを作成することです(実装するのはそれほど面白くありません)。

何か案は ?

4

1 に答える 1

1

SQL CLR内でTransactionScopeを使用すると、常にMSDTCトランザクションにプロモート/エスカレーションされます。SQL 2012でも、これを回避する方法はないようです。

SQL CLRおよびTransactionScopeに関するTechNetから(http://technet.microsoft.com/en-us/library/ms131084.aspx

TransactionScopeは、ローカルおよびリモートのデータソースまたは外部のリソースマネージャーにアクセスしている場合にのみ使用する必要があります。これは、TransactionScopeがコンテキスト接続内でのみ使用されている場合でも、TransactionScopeによって常にトランザクションがプロモートされるためです。

于 2014-05-07T13:38:15.100 に答える