You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 8+EF Core事务超时异常:已设长超时仍15分钟失败求助

问题

在IIS部署的.NET 8 + EF Core项目中执行4个存储过程,已将TransactionScope事务超时设为1小时,DbContext命令超时设为45分钟,但总是在约15分钟后因事务超时终止。这些存储过程在SSMS中的总执行时间为37分钟。

DbContext配置

int timeout = Convert.ToInt32(new TimeSpan(0, 45, 0).TotalSeconds);
options.UseSqlServer(connectionstring,
    x => x.CommandTimeout(timeout)) //timeout

业务代码(MediatR请求处理器中执行)

private static readonly string logLineStartedExecutingMethod = "Started executing method {MethodName}";
private static readonly string logLineFinishedExecutingMethod = "Finished executing method {MethodName} - {RecordCount}";
    
using var trans = new TransactionScope(TransactionScopeOption.RequiresNew, new TimeSpan(1, 0, 0), TransactionScopeAsyncFlowOption.Enabled);

_logger.LogInformation(logLineStartedExecutingMethod, "UspTestA");
var resultA = await _procedureRepository.UspTestAAsync(default, cancellationToken);
_logger.LogInformation(logLineFinishedExecutingMethod, "UspTestA", resultA?.ToString() ?? "0");

_logger.LogInformation(logLineStartedExecutingMethod, "UspTestB");
var resultB = await _procedureRepository.UspTestBAsync(default, cancellationToken);
_logger.LogInformation(logLineFinishedExecutingMethod, "UspTestB", resultB?.ToString() ?? "0");

_logger.LogInformation(logLineStartedExecutingMethod, "UspTestC");
var resultC = await _procedureRepository.UspTestCAsync(request.UserName ?? "Onbekend", default, cancellationToken);
_logger.LogInformation(logLineFinishedExecutingMethod, "UspTestC", resultC?.ToString() ?? "0");         

_logger.LogInformation(logLineStartedExecutingMethod, "UspTestD");
                
// ERROR!!! Transaction timeout after approx. 15 minutes
    
var resultD = await _procedureRepository.UspTestDAsync(default, cancellationToken);
_logger.LogInformation(logLineFinishedExecutingMethod, "UspTestD", resultD?.ToString() ?? "0");

trans.Complete();

异常信息

System.Transactions.TransactionException: 该操作对于事务的状态无效。

System.TimeoutException: 事务超时
--- 内部异常堆栈跟踪结束 ---

在 System.Transactions.TransactionState.EnlistPromotableSinglePhase(InternalTransaction tx, IPromotableSinglePhaseNotification promotableSinglePhaseNotification, Transaction atomicTransaction, Guid promoterType)
在 System.Transactions.Transaction.EnlistPromotableSinglePhase(IPromotableSinglePhaseNotification promotableSinglePhaseNotification, Guid promoterType)
在 System.Transactions.Transaction.EnlistPromotableSinglePhase(IPromotableSinglePhaseNotification promotableSinglePhaseNotification)
在 Microsoft.Data.SqlClient.SqlInternalConnection.EnlistNonNull(Transaction tx)
在 Microsoft.Data.ProviderBase.DbConnectionPool.PrepareConnection(DbConnection owningObject, DbConnectionInternal obj, Transaction transaction)
在 Microsoft.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
在 Microsoft.Data.ProviderBase.DbConnectionPool.WaitForPendingOpen()
--- 上一位置中堆栈跟踪结束 ---
在 Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenInternalAsync(Boolean errorsExpected, CancellationToken cancellationToken)
在 Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenInternalAsync(Boolean errorsExpected, CancellationToken cancellationToken)
在 Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenAsync(CancellationToken cancellationToken, Boolean errorsExpected)
在 Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
在 Microsoft.EntityFrameworkCore.Query.Internal.FromSqlQueryingEnumerable1.AsyncEnumerator.InitializeReaderAsync(AsyncEnumerator enumerator, CancellationToken cancellationToken) 在 Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func4 operation, Func4 verifySucceeded, CancellationToken cancellationToken) 在 Microsoft.EntityFrameworkCore.Query.Internal.FromSqlQueryingEnumerable1.AsyncEnumerator.MoveNextAsync()
在 Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable1 source, CancellationToken cancellationToken) 在 Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable1 source, CancellationToken cancellationToken)
在 Data.StoredProcedures.DbContextExtensions.SqlQueryAsync[T](DbContext db, String sql, Object[] parameters, CancellationToken cancellationToken)

分析与解决方案

核心原因

代码里设置的TransactionScope超时被系统层面的限制覆盖了:

  1. MSDTC默认超时:Windows分布式事务协调器(MSDTC)默认事务超时为15分钟,当事务因多连接操作被提升为分布式事务时,会触发这个系统级限制。
  2. IIS应用池回收/闲置超时:IIS应用池默认闲置超时和定时回收间隔也在15分钟左右,会直接终止进程导致事务中断。

需要调整的额外配置项

1. 修改MSDTC事务超时

  • 打开「组件服务」→「计算机」→「我的电脑」→「分布式事务协调器」→「本地DTC」,右键选择属性
  • 切换到「事务超时」选项卡,将超时时间改为3600秒(1小时)
  • 重启MSDTC服务使设置生效

2. 调整IIS应用池参数

  • 打开IIS管理器,找到目标应用池,右键选择「高级设置」
  • 在「进程模型」下,将「闲置超时(分钟)」设置为大于37分钟的数值(比如40)
  • 在「回收」下,将「固定时间间隔(分钟)」设为0(禁用定时回收)或远大于执行时间的数值

3. 优化EF Core连接复用(避免事务提升)

异步操作中频繁开关连接会导致事务被提升为分布式事务,可在TransactionScope内保持连接打开:

// 在TransactionScope内提前打开连接
await _dbContext.Database.OpenConnectionAsync(cancellationToken);
try
{
    // 执行所有存储过程逻辑
}
finally
{
    await _dbContext.Database.CloseConnectionAsync();
}

4. 检查SQL Server远程查询超时

如果存储过程涉及跨服务器查询,SQL Server默认远程查询超时为600秒(10分钟),需调整:

sp_configure 'remote query timeout', 2220; -- 37分钟=2220秒
RECONFIGURE;

额外建议

  • 尽量避免长时间运行的事务,这类事务会占用数据库锁资源,影响其他业务。可考虑拆分存储过程为独立事务,或通过批量处理、异步队列优化执行时间。
  • 排查单个存储过程的执行性能,看是否存在索引缺失、逻辑冗余等瓶颈,从根源缩短执行时长。

内容的提问来源于stack exchange,提问作者Odrai

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 23:19:50