【问题标题】:Using TransactionScope with Stored Procedure Transaction does not work将 TransactionScope 与存储过程事务一起使用不起作用
【发布时间】:2018-07-03 15:09:39
【问题描述】:

据我了解,在存储过程中包装 T-SQL BEGIN / COMMIT TRANSACTION 时,C# TransactionScope 仍然可以工作。

我有以下 C# 方法,它首先执行 EF Save,然后调用具有自己事务的存储过程,然后通过 HTTP 调用外部服务

public async Task DoSomething(MyDto dto)
{
        using (var scope = new TransactionScope())
        {
            //Save First
            var myEntity = await _dbContext.MyEntity.Where(x=>x.Id == dto.Id).SingleOtDefaultAsync();

            // Assign properties here from dto to MyEntity and then save entity             
            await _dbContext.SaveChangesAsync();

            // call stored procedure that has its own transaction
            _dbContext.prcDoExtraWork(dto.Id);

            // call external service using Http             
            await _httpClient.PostAsync(url,somecontent)

            scope.Complete();
        }
}

存储过程:

CREATE PROCEDURE [dbo].[prcDoExtraWork]
    @ID INT 
AS
BEGIN
    SET NOCOUNT ON;
    SET ANSI_WARNINGS ON;
    SET XACT_ABORT ON;     

    BEGIN TRY
        BEGIN TRANSACTION
            // modify data and  inserts records into tables
        COMMIT TRANSACTION

        SELECT 1 AS `Result`
    END TRY
    BEGIN CATCH
        IF (XACT_STATE() <> 0)
        BEGIN       
            ROLLBACK TRANSACTION

            IF @ErrorMessage IS NULL
            BEGIN
                SET @ProcName = ERROR_PROCEDURE();
                SET @ErrorMessage = ERROR_MESSAGE();
                SET @ErrorNumber = ERROR_NUMBER();
                SET @ErrorSeverity = ERROR_SEVERITY();
                SET @ErrorState = ERROR_STATE();
            END

            EXEC prcErrorHandler @ProcName = @ProcName, 
                                 @ErrorMessage = @ErrorMessage, 
                                 @ErrorSeverity = @ErrorSeverity,
                                 @ErrorState = @ErrorState, 
                                 @ErrorNumber = @ErrorNumber

            SELECT 0 AS `Result`
        END
    END CATCH

    SET XACT_ABORT OFF;
END

问题1:通过http调用外部服务失败,我的预期是存储过程插入或修改的任何记录都会回滚。

然而这并没有发生。我仍然看到数据库中的新记录

问题 2

为了解决上述错误,我必须启用 TransactionScopeAsyncFlowOption,因为我使用的是异步方法

using (var scope = new TransactionScope(TransactionScopeOption.Required, TransactionScopeAsyncFlowOption.Enabled))
    {

     // do your stuff
     scope.complete();
   }

但是现在在 scope.complete() 上出现错误

交易操作无法执行,因为有 处理此事务的待处理请求

System.Transactions.TransactionAbortedException:事务有 中止。 ---> System.Data.SqlClient.SqlException:事务 操作无法执行,因为有待处理的请求 处理这笔交易。在 System.Data.SqlClient.SqlConnection.OnError(SqlException 异常, Boolean breakConnection, Action`1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler、SqlDataReader 数据流、 BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean & dataReady) 在 System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler、SqlDataReader 数据流、 BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) 在 System.Data.SqlClient.TdsParser.TdsExecuteTransactionManagerRequest(字节 [] 缓冲区,TransactionManagerRequestType 请求,字符串 transactionName, TransactionManagerIsolationLevel isoLevel,Int32 超时, SqlInternalTransaction 事务,TdsParserStateObject stateObj, 布尔 isDelegateControlRequest) 在 System.Data.SqlClient.SqlInternalConnectionTds.ExecuteTransactionYukon(TransactionRequest transactionRequest,字符串 transactionName,IsolationLevel iso, SqlInternalTransaction 内部事务,布尔值 isDelegateControlRequest) 在 System.Data.SqlClient.SqlDelegatedTransaction.SinglePhaseCommit(SinglePhaseEnlistment 登记)---内部异常堆栈跟踪结束---在 System.Transactions.TransactionStateAborted.EndCommit(InternalTransaction tx) 在 System.Transactions.CommittableTransaction.Commit() 在 System.Transactions.TransactionScope.InternalDispose() 在 System.Transactions.TransactionScope.Dispose() 在 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.d__343.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 XXXXXXXXXXXXX.MyDetailController.d__9.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 System.Web.Mvc.Async.TaskAsyncActionDescriptor.EndExecute(IAsyncResult asyncResult) 在 System.Web.Mvc.Async.AsyncControllerActionInvoker.c__DisplayClass37.b__36(IAsyncResult asyncResult) 在 System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult) 在 System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.b__3d() 在 System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.c__DisplayClass46.b__3f() 在 System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.c__DisplayClass46.b__3f() 在 System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.c__DisplayClass46.b__3f() 在 System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters(IAsyncResult asyncResult) 在 System.Web.Mvc.Async.AsyncControllerActionInvoker.c__DisplayClass21.c__DisplayClass2b.b__1c() 在 System.Web.Mvc.Async.AsyncControllerActionInvoker.c__DisplayClass21.b__1e(IAsyncResult asyncResult)

【问题讨论】:

    标签: sql-server entity-framework ado.net transactionscope msdtc


    【解决方案1】:

    我想我找到了。
    我通过启用TransactionScopeAsyncFlowOption 解决了第一个问题,因为我使用的是异步方法

            using (var scope = new TransactionScope(TransactionScopeOption.Required, TransactionScopeAsyncFlowOption.Enabled))
            {
    
             // do your stuff
             scope.complete();
           }
    

    第二期
    存储过程根据成功或错误返回 1 或 0。 C# 代码不关心返回结果的值,但是我没有评估存储过程的返回结果。所以要解决我必须调用'SingleOrDefault`

    _dbContext.prcDoExtraWork(dto.Id).SingleOrDefault()

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多