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

如何在.NET Core中使用TransactionScope及解决上下文已释放错误

报错原因
  • 核心触发原因是控制器调用异步方法CreateTransaction时未添加await关键字:CreateTransaction为返回Task的异步方法,无await时控制器方法会直接执行后续逻辑并返回响应,ASP.NET Core请求生命周期结束后,依赖注入容器会自动释放注入的TransactionContext实例(默认注册为Scoped生命周期,与请求绑定),此时仍在后台运行的CreateTransaction方法访问已释放的上下文就会抛出该错误。
  • 现有事务实现还存在多处逻辑问题:
    • 事务操作全部完成后未调用Commit()提交,using块结束后事务会自动回滚,所有修改都不会生效
    • 账户更新逻辑错误,两次Update调用均针对receiverAccount,转出账户senderAccount的修改不会被提交
    • 金额计算逻辑存在隐性问题:receiverAccount.Amount = senderAccount.Amount + transaction.Amount依赖sender扣减后的金额计算,后续如果修改sender的扣减逻辑容易连带出错,建议直接使用receiver原有金额累加交易金额
    • 所有数据库操作均使用同步方法,在异步方法中混用同步IO容易引发线程池阻塞问题
修复方案

基础修复(使用EF Core原生事务)

如果是单DbContext的事务场景,直接使用EF Core自带的事务实现更轻量,修改代码如下:

  1. 修复控制器调用逻辑,添加await
[HttpPost]
public async Task<ActionResult<TransactionDto>> CreateNewTrasaction(TransactionDto accountCreateDto)
{
    var commandModel = _mapper.Map<TransactionHistory>(accountCreateDto);
    // 等待异步事务方法执行完成
    await _transactionRepository.CreateTransaction(commandModel);
    var accountReadDto = _mapper.Map<AccountReadDto>(commandModel);
    return Ok();
}
  1. 修复Repository的事务实现
public async Task CreateTransaction(TransactionHistory transaction)
{
    // 使用异步开启事务
    using IDbContextTransaction transactionContext = await _transContext.Database.BeginTransactionAsync();
    try
    {
        transaction.CreatedDate = DateTime.UtcNow;
        _transContext.TransactionHistories.Add(transaction);
        await _transContext.SaveChangesAsync();

        // 使用异步查询
        var senderAccount = await _transContext.Accounts.FirstOrDefaultAsync(x => x.AccountNo == transaction.AccountNo);
        var receiverAccount = await _transContext.Accounts.FirstOrDefaultAsync(x => x.AccountNo == transaction.ReceiverAccount);

        // 前置校验,避免空引用和余额不足
        if (senderAccount == null || receiverAccount == null || senderAccount.Amount < transaction.Amount)
        {
            throw new InvalidOperationException("交易参数非法,无法完成转账");
        }

        senderAccount.Amount -= transaction.Amount;
        receiverAccount.Amount += transaction.Amount;

        // 同时更新两个账户
        _transContext.Accounts.Update(senderAccount);
        _transContext.Accounts.Update(receiverAccount);
        await _transContext.SaveChangesAsync();

        // 提交事务
        await transactionContext.CommitAsync();
    }
    catch (Exception ex)
    {
        // 异常时回滚事务
        await transactionContext.RollbackAsync();
        throw;
    }
}

TransactionScope使用方案

如果需要跨多个DbContext或多个数据源实现分布式事务,可以使用TransactionScope,使用前先安装NuGet包System.Transactions.Local,实现代码如下:

public async Task CreateTransactionWithScope(TransactionHistory transaction)
{
    // 必须指定TransactionScopeAsyncFlowOption.Enabled,才能支持异步上下文下的事务流转
    using var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled);
    try
    {
        transaction.CreatedDate = DateTime.UtcNow;
        _transContext.TransactionHistories.Add(transaction);
        await _transContext.SaveChangesAsync();

        var senderAccount = await _transContext.Accounts.FirstOrDefaultAsync(x => x.AccountNo == transaction.AccountNo);
        var receiverAccount = await _transContext.Accounts.FirstOrDefaultAsync(x => x.AccountNo == transaction.ReceiverAccount);

        if (senderAccount == null || receiverAccount == null || senderAccount.Amount < transaction.Amount)
        {
            throw new InvalidOperationException("交易参数非法,无法完成转账");
        }

        senderAccount.Amount -= transaction.Amount;
        receiverAccount.Amount += transaction.Amount;

        _transContext.Accounts.Update(senderAccount);
        _transContext.Accounts.Update(receiverAccount);
        await _transContext.SaveChangesAsync();

        // 所有操作执行成功后提交事务
        scope.Complete();
    }
    catch (Exception ex)
    {
        // 无需手动回滚,未调用Complete的scope在释放时会自动回滚所有操作
        throw;
    }
}

注意:TransactionScope依赖环境的分布式事务支持,Windows环境下依赖MSDTC服务,Linux环境下需要依赖相应的分布式事务组件,跨数据库/跨服务场景才建议使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 23:48:02