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

WPF中使用TransactionScope与Task.WhenAll并行MySQL任务报错求助

问题分析与修正方案

错误根源

你的代码抛出KeyNotFoundException的核心原因是事务上下文被提前销毁:

  • 在foreach循环里,你把异步任务添加到列表后,立刻结束了TransactionScope的using块,此时事务已经被释放,但CallSQL1和CallSQL2的异步任务还在后台执行,当任务尝试关联事务上下文时,找不到对应条目就会触发该异常。
  • 事务的Complete()调用时机完全错误,你在任务还没执行完成就提交了事务,彻底失去了事务的原子性保障。
  • 多个连接的任务混在同一个列表中,事务边界混乱,无法保证单个连接下两个SQL操作的事务一致性。

修正后的代码

我们需要把每个数据库连接的事务逻辑独立封装,确保事务在异步任务执行完成后再提交或回滚,同时实现多连接的并行处理:

List<Task> disTaskList = new List<Task>();
foreach (string connStr in connectionString)
{
    // 每个连接对应一个独立的事务处理任务,加入并行列表
    disTaskList.Add(ProcessSingleConnectionAsync(connStr));
}
// 等待所有连接的处理任务完成
await Task.WhenAll(disTaskList);

// 封装单个连接的事务与并行SQL操作
private async Task ProcessSingleConnectionAsync(string connStr)
{
    // 启用异步事务流,确保异步操作能继承事务上下文
    using (TransactionScope transactionScope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
    {
        try
        {
            // 并行执行当前连接下的两个SQL操作,等待全部完成
            await Task.WhenAll(CallSQL1(connStr), CallSQL2(connStr));
            // 两个操作都无异常,提交事务
            transactionScope.Complete();
        }
        catch (Exception ex)
        {
            Console.WriteLine($"调用SQL出错:{ex.Message}");
            // 无需手动回滚,using块结束时,未Complete的事务会自动回滚
        }
    }
}

关键修正点说明

  1. 事务边界独立:每个数据库连接的事务逻辑封装到ProcessSingleConnectionAsync方法中,确保不同连接的事务互不干扰。
  2. 正确的事务生命周期:事务会一直持有到当前连接的两个SQL操作全部执行完成,避免了上下文提前销毁的问题。
  3. 事务原子性保障:只有当CallSQL1和CallSQL2都成功执行后,才会调用Complete()提交事务;任何一个操作抛出异常,事务都会在using块结束时自动回滚。
  4. 多连接并行:外层的Task.WhenAll负责并行处理所有数据库连接的任务,真正实现了效率提升。

额外注意事项

  • 确保你的MySQL驱动支持TransactionScope的异步操作(推荐使用最新版本的MySqlConnector)。
  • CallSQL1和CallSQL2中的异常要正确抛出,不要在内部吞掉,否则事务无法感知到错误进行回滚。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 17:47:18