transactionscope 中的异步 处理 异常_.NET Core中TransactionScope事务处理方法介绍及注意事项...
作者:依乐祝
原文链接:https://www.cnblogs.com/yilezhu/p/10170712.html
今天在写CzarCms的UnitOfWork的使用使用到了这个TransactionScope事务,因此对它进行了相关资料的查阅并记录如下,希望对大伙在.NET Core中使用有所帮助。
写在前面
您是否曾尝试使用C#代码来实现事务?通常,我们在SQL中一次执行多个Insert / Update语句的话可能就会使用到事务。事务遵循ACID(原子性,一致性,隔离性,持久性)规则,这样所有的语句要么全部执行成功要么全部被取消并执行回滚操作。而我们今天要讲的TransactionScope则可以允许我们在应用程序级别实现这个过程。在某些情况下,您可能需要在同一个数据库甚至多个数据库(分布式事务)中执行不同的操作,或者由于某些其他约束,它无法在数据库级别来完成,或者应用程序的开发人员对数据库的接触较少,那么这时候TransactionScope将会让你游刃有余。
什么是TransactionScope呢?
TransactionScope作为System.Transactions的一部分被引入到.NET 2.0。同时SqlClient for .NET Core 从 2.1 及以上版本开始提供对System.Transactions的支持 。它是一个类,它提供了一种简单的方法,可以将一组操作作为事务的一部分来进行处理,而不必担心场景背后的复杂性。如果某个操作在执行的过程中失败的话,则整个事务将失败并执行回滚操作,从而撤消已完成的所有操作。所有这些都将由框架处理,从而确保数据的一致性。
如何使用TransactionScope呢?
要使用它,您需要添加System.Transactions的引用,如果你使用的是.net core的话。这个引用被包含在netcoreapp2.2\System.Transactions.Local.dll
中, 该引用是框架库的一部分(通常默认情况下不会自动添加)。添加后,在我们想要使用它的地方添加名称空间 System.Transactions即可。代码如下所示:
在上面的代码中我们可以看到我们在创建TransactionScope实例时使用了using
语句块及Disposable块,它确保了当dispose离开块并结束事务范围时调用dispose来进行资源的释放。在一个Transaction范围中,我们可以做多个连接甚至链接到不同数据库的操作的,如下所示:
下面我们使用两个不同的数据库连接字符串来连接不同的数据库。当然我们也可以根据我们的业务要求使用尽可能多数据库。我们也可以再事务中嵌套事务。如下代码所示:
这里最顶层的事务范围称为根范围。另外这里需要注意的是即使通过调用scope.Complete()完成内部事务(上面的OtherTransaction ),如果由于各种原因无法调用rootscope complete,那么整个事务也将被回滚包括内部的事务。
*注意:执行分布式trsanctions时,您可能会收到以下异常之一*
服务器上的MSDTC不可用
已禁用分布式事务管理器(MSDTC)的网络访问。
这两个错误都是由于同样的原因,第一个是在数据库和应用程序是同一个服务器时发生的,而在另一个则是服务跟数据库分别部署在两台服务器上。对于同一台服务器,请转到run-> cmd-> services.msc。运行名为Distributed Transaction Coordinator的服务并自动启动启动类型,以便在系统重新启动时再次启动它。对于2,你可能需要参照这个链接的内容进行相应的设置
TransactionScope 类提供了多个重载构造函数,它们接受 TransactionScopeOption 类型的枚举,而该枚举定义事务范围行为。
TransactionScope对象有以下三个选项:
Required:联接环境事务,或者在环境事务不存在的情况下创建新的环境事务。
RequiresNew:成为新的根范围,也就是说,启动一个新事务并使该事务成为其自己范围中的新环境事务。
Suppress:根本不参与事务。因此没有环境事务。
如果用 Required] 实例化范围并且存在环境事务,则该范围会联接该事务。相反,如果不存在环境事务,该范围就会创建新的事务并成为根范围。这是默认值。在使用 Required时,无论范围是根范围还是仅联接环境事务,该范围中的代码都不需要有不同的行为。该代码在这两种情况下的行为应相同。
如果用 RequiresNew 实例化范围,则它始终为根范围。它会启动一个新事务,并且其事务成为该范围中的新环境事务。
如果用 Suppress 实例化范围,则无论是否存在环境事务,范围都从不参与事务。始终使用此值实例化的作用域具有null作为其环境事务。
下面来让我们看一组实例代码:
在这里,我们使用不同的TransactionScopeOptions在父事务下创建了三个事务。默认情况下,范围是required ,这里父事务就是采用的这个默认参数进行创建的。它是一个创建新事务的根范围,并将其标记为环境事务。scope1也是使用required创建的,因为我们已经有了一个环境事务(范围),所以它加入到父事务中。scope2是使用RequiresNew选项创建的,这意味着它是一个独立于环境事务处理的新事务。scope3是用suppress创建的选项,这意味着它不参与任何环境事务。无论环境事务是否成功执行,它都会被执行。父(全局)范围完成后,将提交所有环境事务。
注意点
EF Core 依赖数据库提供程序以实现对 System.Transactions 的支持。虽然支持在 .NET Framework 的 ADO.NET 提供程序之间十分常见,但最近才将 API 添加到 .NET Core,因此支持并未得到广泛应用。如果提供程序未实现对 System.Transactions 的支持,则可能会完全忽略对这些 API 的调用。SqlClient for .NET Core 从 2.1 及以上版本开始支持 System.Transactions。如果尝试在低版本中 如.NET Core 2.0中尝试使用该功能将引发异常。
自版本 2.1 起,.NET Core 中的 System.Transactions 实现将不包括对分布式事务的支持,因此不能使用
TransactionScope
或CommittableTransaction
来跨多个资源管理器协调事务。主要是不依赖windows中的mstsc功能。异步方法使用时需要注意:
在下面的例子中,我们在
TransactionScope
内部使用await
。using(var scope = new TransactionScope()){ var groups = await Context.ProductGroups.ToListAsync()。ConfigureAwait(false);}
看起来没有问题,但它会抛出一个
System.InvalidOperationException:``A TransactionScope must be disposed on the same thread that it was created.
原因是默认情况下
TransactionScope
不会从一个线程切换到另一个线程。为了解决这个问题,我们必须使用TransactionScopeAsyncFlowOption.Enabled
:using(var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled)){ var groups = await Context.ProductGroups.ToListAsync()。ConfigureAwait(false);}
现在应该可以了吧?这取决于下面的情况。
如果我们使用和不使用
TransactionScopeAsyncFlowOption这个
选项的时候都使用了相同的数据库连接,并且第一次执行的时候没有使用这个选项,那么我们会得到另一个异常:System.InvalidOperationException:``Connection currently has transaction enlisted. Finish current transaction and retry.
换句话说,由于第一个访问的原因,第二个会话将会失败。如下代码所示:
想象一下,如果第一个调用是在第三方库或您正在使用的框架中完成的,二您不了解其中的代码 - 如果您之前没有看到此错误,那么你讲无从下手来解决这个问题。
总结
本文带着大家熟悉了一遍TransactionScope并对其使用进行了介绍!同时介绍了在.NET Core中使用TransactionScope的一些注意事项!希望对大家有所帮助.
transactionscope 中的异步 处理 异常_.NET Core中TransactionScope事务处理方法介绍及注意事项...相关推荐
- transactionscope 中的异步 处理 异常_协程中的取消和异常 | 异常处理详解
开发者们通常会在打磨应用的正常功能上花费很多时间,但是当应用出现一些意外情况时,给用户提供合适的体验也同样重要.一方面来讲,对用户来说,目睹应用崩溃是个很糟糕的体验:而另一方面,在用户操作失败时,也必 ...
- java中什么是运行异常_在java中最常用的运行时异常是什么?
我从不会抛出NullPointerException.对我来说,它是一个出现在代码中当出现问题时,需要开发人员看看会发生什么.然后(s)他固定的原因,它不会再次发生. 我使用IllegalStateE ...
- 计算机网络设置中的网关是什么设备,网关是什么_网关的作用与设置方法介绍 一看就明白...
网关是什么?对于普通的用户来说,电脑网关不是很明白的,不过接触电脑多了之后,大家也会常常会听到"网关"这个词,那么问题就来了,这个网关是什么意思呢?它又有哪些作用呢?今晚,智能手机 ...
- .net mysql transactionscope_TransactionScope事务处理方法介绍及.NET Core中的注意事项
原标题:TransactionScope事务处理方法介绍及.NET Core中的注意事项 作者:依乐祝 原文链接:https://www.cnblogs.com/yilezhu/p/10170712. ...
- Linux环境中堆栈和堆相关内存损坏的基本原理和调试方法介绍
本文讲的是Linux环境中堆栈和堆相关内存损坏的基本原理和调试方法介绍, 前言 建议阅读本文之前,你对ARM组件的有个基本了解,本文会先为你介绍32位Linux环境中进程的内存布局,然后再介绍堆栈和堆 ...
- TIA博途S7-1200中实现高低字节或高低字调换的几种方法介绍
TIA博途S7-1200中实现高低字节或高低字调换的几种方法介绍 例如S7-1200与某些上位机进行通信时,读写的浮点数的存储方式与上位机不同,即高低字或字节是相反的,此时读取的数据是不对的,需要将高 ...
- 诛仙3怎么一直服务器维护,诛仙3游戏老是掉线怎么办_诛仙3游戏掉线解决方法介绍...
诛仙3游戏老是掉线怎么办_诛仙3游戏掉线解决方法介绍 诛仙3经常掉线但又不是网速的锅,通常玩家们会把锅甩给服务器,但是甩锅依然解决不了掉线问题,今天小编为各位玩家带来诛仙3游戏掉线怎么办解决方法,一起 ...
- java异常_聊聊Java中的异常及处理
前言 在编程中异常报错是不可避免的.特别是在学习某个语言初期,看到异常报错就抓耳挠腮,常常开玩笑说编程1分钟,改bug1小时.今天就让我们来看看什么是异常和怎么合理的处理异常吧! 异常与error介绍 ...
- java 异常处理发生异常_处理Java中的异常
java 异常处理发生异常 每个程序员都希望编写一个完美的程序. 也就是说,程序运行时没有任何障碍. 好吧,如果希望是马,乞g就会骑. 除了程序员的所有愿望之外,有时还会发生无法预料的情况. 在Jav ...
最新文章
- App 运营的指标具体都有哪些?(二)
- 3704对象关闭时_JVM 通过逃逸分析就能让对象在栈上分配?没那么简单!
- 使用wlan接收器经常重新登录怎么办
- 传统公司部署OpenStack(t版)简易介绍(八)——Dashboard模块部署
- MATLAB中,信号的频谱图该怎么绘制?横坐标如何标注出频率值?
- 蜜罐网络(开源汇总)MHN
- 网关策略跟计算机名有关系吗,交换机网关与与之相连的计算机的网关有没有必然关系...
- C语言把浮点数转换为字符串
- 【Python】模块学习之Timer定时任务,递归定时自调获取博客浏览量
- 基于Java的Cplex入门
- 【多元统计分析】11.回归方程与回归系数的显著性检验
- 【调剂】上海应用技术大学2021年硕士研究生招生考试调剂信息
- tplink710n无线打印服务器,tplink710n设置
- 详细讲解半加器、全加器、四位全加器,并使用FPGA实现半加器、全加器
- spark sample采样
- xp大容量u盘补丁_u盘128g 个性 大容量电脑系统修复
- 基于java的个人日程管理系统mysql
- 利用百度ocr识别验证码
- 用HTML写一首诗并配上图片,需要满足诗的格式
- ddz指标最佳数值_大单分差指标ddz如何解析资金流向与筹码分布