如何在SQLCLR中使用TransactionScope而不升级到MSDTC

ssc*_*enb 5 c# sqlclr sql-server-2008-r2

我们的许多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();
                }
            }
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

  2. 用于执行CLR过程的SQL脚本

    BEGIN TRANSACTION
    
    exec dbo.ClrWithTrans "select * from sys.tables";
    exec dbo.ClrWithScope "select * from sys.tables"; /* <- DOES NOT WORK! */
    
    ROLLBACK TRANSACTION
    
    Run Code Online (Sandbox Code Playgroud)
  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.
    
    Run Code Online (Sandbox Code Playgroud)

WIHTOUT"BEGIN TRANSACTION"语句,dbo.ClrWithScope调用工作正常.我想在登录.Net Framework时不考虑SQLServer启动的事务.

是否有解决方案来解决这个问题.一个想法是手动创建一个SqlTransaction并使TransactionScope使用此事务,但我不知道如何做到这一点.另一种解决方案是在所有DAL代码中创建一个特殊情况(实现起来并不是很有趣).

有任何想法吗 ?

Bat*_*ech 1

在 SQL CLR 中使用 TransactionScope 将始终提升/升级为 MSDTC 事务。即使在 SQL 2012 中,似乎也没有任何方法可以解决这个问题。

来自 TechNet 关于 SQL CLR 和 TransactionScope ( http://technet.microsoft.com/en-us/library/ms131084.aspx )

仅当访问本地和远程数据源或外部资源管理器时才应使用 TransactionScope。这是因为 TransactionScope 始终会导致事务升级,即使它仅在上下文连接中使用。