你可能不知道这一点,在 .NET Framework 4.5.0  版本中包含有一个关于 System.Transactions.TransactionScope 在与 async/await 一起工作时会产生的一个严重的 bug 。由于这个错误,TransactionScope 不能在异步代码中正常操作,它可能更改事务的线程上下文,导致在处理事务作用域时抛出异常。

这是一个很大的问题,因为它使得涉及事务的异步代码极易出错。

好消息是,在 .NET Framework 4.5.1 版本中,微软发布了这个 "异步连接" 错误的修复程序。作为开发者的我们需要明确的做到以下两点:

  • 如果说你在 TransactionScope 代码中使用 async/await,你需要将框架升级到 .NET 4.5.1 或以上版本。
  • 在有包装异步代码的 TransactionScope 的构造函数中指定 TransactionScopeAsyncFlowOption.Enabled .

TransactionScope

System.Transactions.TransactionScope 类允许我们在事务中包装数据库代码,基础结构代码,有时甚至包括第三方代码(如果第三方库支持)。 然后,代码只在我们实际想提交(或完成)事务时才执行操作。

只要 TransactionScope 中的所有代码都在同一线程上执行,调用堆栈上的所有代码都可以与代码中定义的 TransactionScope 一起参与。 我们可以在父事务作用域内嵌套作用域或创建新的独立作用域。 我们甚至可以创建 TransactionScope 的副本,并将副本传递到另一个线程并连接回调用线程。 通过使用事务作用域包装代码,使用隐式事务模型,也称为环境事务。

如下代码:

public void TransactionScopeAffectsCurrentTransaction() {Debug.Assert(Transaction.Current == null);using (var tx = new TransactionScope()) {Debug.Assert(Transaction.Current != null);SomeMethodInTheCallStack();tx.Complete();}Debug.Assert(Transaction.Current == null);
}private static void SomeMethodInTheCallStack()
{Debug.Assert(Transaction.Current != null);
}

正如我们可以看到使用块外面的 Transaction.Current 属性为 null。 在使用块内 Transaction.Current 属性不为 null。 即使在调用堆栈中的方法像 SomeMethodInTheCallStack 可以访问 Transaction.Current,前提是它要被包裹在使用块中。
TransactionScope 的好处是,如果需要,本地事务自动升级到分布式事务。 事务范围还简化了对事务的编程,如果你喜欢隐式的显式。

TransactionFlowInterruptedException

当 async / await 引入了 C#5.0 和 .NET 4.5,一个小小的细节被完全忘记。 当在一个包装 TransactionScope 下调用一个异步方法时,编译器引入的底层状态机没有正确地“浮动”事务(原文 "float")。 让我们将我们关于 TransactionScope 如何在同步代码中工作的知识应用到异步代码。

有如下代码:

public async Task TransactionScopeWhichDoesntBehaveLikeYouThinkItShould() {using (var tx = new TransactionScope()){await SomeMethodInTheCallStackAsync().ConfigureAwait(false);tx.Complete();}
}private static async Task SomeMethodInTheCallStackAsync()
{await Task.Delay(500).ConfigureAwait(false);
}

不幸的是,它不工作的方式。 代码几乎(但只是几乎)执行类似于同步版本,但如果项目这个代码是写在目标 .NET Framework 4.5,当我们到达使用块的结束,并尝试处置 TransactionScope 时抛出以下异常 :
  System.InvalidOperationException:一个 TransactionScope 必须处理在它被创建的同一个线程。

为了使TransactionScope和async正常工作,我们需要将我们的项目升级到.NET 4.5.1。

TransactionScopeAsyncFlowOption

在 .NET 4.5.1中,TransactionScope 有一个名为 TransactionScopeAsyncFlowOption 的新枚举,可以在构造函数中提供。 您必须通过指定,明确地选择跨线程连续的事务流,如下:

using (var tx = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{await SomeMethodInTheCallStackAsync().ConfigureAwait(false);tx.Complete();
}

你可能很好奇,默认的 TransactionScopeAsyncFlowOption 是 Suppress(阻止的),因为微软想避免破坏 .NET 4.5.0 版本中代码库中行为。

最后

使用 TransactionScope 结合 async / await 时,你应该更新所有使用 TransactionScope 的代码路径以启用 TransactionScopeAsyncFlowOption.Enabled 。 这样才能使事务能够正确地流入异步代码,防止在TransactionScope下使用时业务逻辑不正常。

英文原文:TransactionScope and Async/Await. Be one with the flow!

原文地址:https://www.cnblogs.com/god--love-you/p/6076265.html

转载于:https://www.cnblogs.com/hzz521/p/9598952.html

TransactionScope 与 Async/Await相关推荐

  1. setTimeout、setInterval、promise、async/await的顺序详解(多种情况,非常详细~)

    本文很长,列举的情况很多. 在阅读本文之前,如果您有充足的时间,请新建一个项目与本文一同实践. 每段代码都有对应的解释,但是自己动手尝试印象才会更深哦~ setInterval:表示多久执行一次,需要 ...

  2. C# async await 学习笔记2

    C# async await 学习笔记1(http://www.cnblogs.com/siso/p/3691059.html) 提到了ThreadId是一样的,突然想到在WinForm中,非UI线程 ...

  3. promise 和 async await区别

     什么是Async/Await? async/await是写异步代码的新方式,以前的方法有回调函数和Promise. async/await是基于Promise实现的,它不能用于普通的回调函数. as ...

  4. angular2 学习笔记 ( Rxjs, Promise, Async/Await 的区别 )

    Promise 是 ES 6 Async/Await 是 ES 7 Rxjs 是一个 js 库 在使用 angular 时,你会经常看见这 3 个东西. 它们都和异步编程有关,有些情况下你会觉得用它们 ...

  5. async await:比requests 更强大

    最近公司 Python 后端项目进行重构,整个后端逻辑基本都变更为采用"异步"协程的方式实现.看着满屏幕经过 async await(协程在 Python 中的实现)修饰的代码,我 ...

  6. @async 默认线程池_.NET Web应用中为什么要使用async/await异步编程?

    布莱恩特:.NET Core开发精选文章目录,持续更新,欢迎投稿!​zhuanlan.zhihu.com 前言 1.什么是async/await? await和async是.NET Framework ...

  7. Atitit. Async await 优缺点 异步编程的原理and实现 java c# php

    Atitit. Async await 优缺点 异步编程的原理and实现 java c# php 1. async & await的来源1 2. 异步编程history1 2.1. 线程池 2 ...

  8. 8张图让你一步步看清 async/await 和 promise 的执行顺序

    2019独角兽企业重金招聘Python工程师标准>>> **摘要:**面试必问 原文:8张图帮你一步步看清 async/await 和 promise 的执行顺序 作者:ziwei3 ...

  9. 用 async/await 来处理异步

    引用出处:https://www.cnblogs.com/SamWeb/p/8417940.html 昨天看了一篇vue的教程,作者用async/ await来发送异步请求,从服务端获取数据,代码很简 ...

最新文章

  1. 机器学习:特征选择和降维实例
  2. mysql5.6安装sys库_MySQL5.6数据库优化my.cnf配置
  3. GitHub的10,000个最受欢迎的Java项目-以下是它们使用的顶级库
  4. 输入一个正整数n,计算s=1-1/3+1/5-1/7…前n项之和
  5. 换行与回车(\r \n)的起源以及在编制语言中的使用
  6. 【渝粤教育】广东开放大学 生产与运作管理 形成性考核 (36)
  7. python合并单元格居中_Python实现Excel自动分组合并单元格
  8. PHP:同时发送多个异步ajax请求,但数据却是按同步顺序返回
  9. 百度浏览器内核太低,浏览京东有问题
  10. 顶级区块链开发人员工具:涉及框架、IDE、安全工具、测试网络、区块链预言机和节点服务
  11. 【第三方互联】微博2、创建新浪微博(sina)互联应用
  12. Centos8关闭防火墙
  13. Android Hal层回调APP应用接口
  14. base64编码解码讲解
  15. restore,recover的区别
  16. 计算机一级比分多少,如何在电子表格中打出比分?
  17. 计算股票季度收益率、年收益率和相对收益率并可视化展示。
  18. 全国信息竞赛语言有python吗_2019年全国信息学竞赛有哪些
  19. 安卓android按宽/高缩放图片到指定大小并进行裁剪得到中间部分图片
  20. k8s-重启kubelet服务异常 kubelet.service: main process exited, code=exited, status=1/FAILURE

热门文章

  1. Windows环境部署PbootCMS企业网站管理系统
  2. jQuery进度条插件JQMeter的简单使用
  3. Access用OleDbParameter更新/插入数据
  4. 逆战之微信小程序云开发
  5. 百亿级图数据在快手安全情报的应用与挑战
  6. Grid (基础DP)
  7. 11.declare 命令详解及5种类型用法示例
  8. 2021如何用短信查询高考成绩,2020湖南高考成绩短信查询方式
  9. 百度总裁李彦宏的创业七招
  10. rpm -Uvh 执行顺序