sql-server - 将 TransactionScope 与存储过程事务一起使用不起作用
问题描述
据我了解,在存储过程中TransactionScope
包装 T-SQL 时,C# 仍然可以工作。BEGIN / COMMIT TRANSACTION
我有以下 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 异常,布尔 breakConnection,Action`1 wrapCloseInAction)在 System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj,布尔 callerHasConnectionLock,布尔 asyncClose)在 System.Data.SqlClient.TdsParser System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior,SqlCommand cmdHandler,
解决方案
我想我找到了。
我通过启用解决了第一个问题,TransactionScopeAsyncFlowOption
因为我使用的是异步方法
using (var scope = new TransactionScope(TransactionScopeOption.Required, TransactionScopeAsyncFlowOption.Enabled))
{
// do your stuff
scope.complete();
}
第二个问题
存储过程根据成功或错误返回 1 或 0。C# 代码不关心返回结果的值,但是我没有评估存储过程的返回结果。所以要解决我必须调用'SingleOrDefault`
_dbContext.prcDoExtraWork(dto.Id).SingleOrDefault()
推荐阅读
- javascript - 分隔字符串数组以创建表格行
- apache-spark - emr 上的 pyspark 使用自动广播(即使已禁用)和用于简单 sql 查询的嵌套连接
- html - 将内联块元素添加到表格跨越列时,HTML 表格列的宽度会发生变化
- java - 更改变量时重绘不起作用
- c# - 我不知道为什么,但我的附加力不起作用我有一个刚体 2d,代码看起来正确但它仍然不起作用?
- angular - 从 Observable Array of Objects 迭代 *ngFor 时如何修复 InvalidPipeArgument 错误
- javascript - 如何使用 JavaScript 语言在 Jmeter WebDriver Sampler 中设置 InternetExplorerOptions?
- apache - mod_jk 使用 Lucee 和 Apache 生成不正确的重定向查询字符串
- system-verilog - DPI-C 中 Struct 中的动态数组
- node.js - 使用 Node.js 从 txt 文件中读取坐标