【转】TransactionScope事务处理方法介绍及.NET Core中的注意事项

什么是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即可。代码如下所示:

try{using(TransactionScopescope=newTransactionScope()){// Do Operation 1// Do Operation 2//...// 如果所有的操作都执行成功,则Complete()会被调用来提交事务// 如果发生异常,则不会调用它并回滚事务scope.Complete();}}catch(ThreadAbortExceptionex){// 处理异常}

在上面的代码中我们可以看到我们在创建TransactionScope实例时使用了using 语句块及Disposable块,它确保了当dispose离开块并结束事务范围时调用dispose来进行资源的释放。
在一个Transaction范围中,我们可以做多个连接甚至链接到不同数据库的操作的,如下所示:

using(TransactionScopescope=newTransactionScope()){using(con=newSqlConnection(conString1)){con.Open();// 执行操作 1// 执行操作 2//...}using(con=newSqlConnection(conString2)){con.Open();// 执行操作 1// 执行操作 2//...}scope.Complete();}

下面我们使用两个不同的数据库连接字符串来连接不同的数据库。当然我们也可以根据我们的业务要求使用尽可能多数据库。我们也可以再事务中嵌套事务。如下代码所示:

publicvoidDoMultipleTransaction(){try{using(TransactionScopescope=newTransactionScope()){using(con=newSqlConnection(conString1)){con.Open();// 执行操作1}OtherTransaction();scope.Complete();}}catch(ThreadAbortExceptionex){// 处理异常}}privatevoidOtherTransaction(){using(TransactionScopescope=newTransactionScope()){using(con=newSqlConnection(conString2)){con.Open();// 执行操作}scope.Complete();}}

这里最顶层的事务范围称为根范围。另外这里需要注意的是即使通过调用scope.Complete()完成内部事务(上面的OtherTransaction ),如果由于各种原因无法调用rootscope complete,那么整个事务也将被回滚包括内部的事务。

*注意:执行分布式trsanctions时,您可能会收到以下异常之一*

  1. 服务器上的MSDTC不可用
  2. 已禁用分布式事务管理器(MSDTC)的网络访问。

这两个错误都是由于同样的原因,第一个是在数据库和应用程序是同一个服务器时发生的,而在另一个则是服务跟数据库分别部署在两台服务器上。对于同一台服务器,请转到run-> cmd-> services.msc。运行名为Distributed Transaction Coordinator的服务并自动启动启动类型,以便在系统重新启动时再次启动它。对于2,你可能需要参照这个链接的内容进行相应的设置

TransactionScope 类提供了多个重载构造函数,它们接受 TransactionScopeOption 类型的枚举,而该枚举定义事务范围行为。

TransactionScope对象有以下三个选项:

  • Required:联接环境事务,或者在环境事务不存在的情况下创建新的环境事务。
  • RequiresNew:成为新的根范围,也就是说,启动一个新事务并使该事务成为其自己范围中的新环境事务。
  • Suppress:根本不参与事务。 因此没有环境事务。

如果用 Required] 实例化范围并且存在环境事务,则该范围会联接该事务。 相反,如果不存在环境事务,该范围就会创建新的事务并成为根范围。 这是默认值。 在使用 Required时,无论范围是根范围还是仅联接环境事务,该范围中的代码都不需要有不同的行为。 该代码在这两种情况下的行为应相同。

如果用 RequiresNew 实例化范围,则它始终为根范围。 它会启动一个新事务,并且其事务成为该范围中的新环境事务。

如果用 Suppress 实例化范围,则无论是否存在环境事务,范围都从不参与事务。 始终使用此值实例化的作用域具有null作为其环境事务。

下面来让我们看一组实例代码:

using(TransactionScopescope=newTransactionScope()){// 联接环境事务,或者在环境事务不存在的情况下创建新的环境事务。using(TransactionScopescope1=newTransactionScope(TransactionScopeOption.Required)){// Do Operationscope1.Complete();}//成为新的根范围,也就是说,启动一个新事务并使该事务成为其自己范围中的新环境事务。using(TransactionScopescope2=newTransactionScope(TransactionScopeOption.RequiresNew)){// Do Operationscope2.Complete();}//根本不参与事务。 因此没有环境事务。using(TransactionScopescope3=newTransactionScope(TransactionScopeOption.Suppress)){// Do Operationscope3.Complete();}scope.Complet

在这里,我们使用不同的TransactionScopeOptions在父事务下创建了三个事务。默认情况下,范围是required ,这里父事务就是采用的这个默认参数进行创建的。它是一个创建新事务的根范围,并将其标记为环境事务。scope1也是使用required创建的,因为我们已经有了一个环境事务(范围),所以它加入到父事务中。scope2是使用RequiresNew选项创建的,这意味着它是一个独立于环境事务处理的新事务。scope3是用suppress创建的选项,这意味着它不参与任何环境事务。无论环境事务是否成功执行,它都会被执行。父(全局)范围完成后,将提交所有环境事务。

注意点

  1. 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. 自版本 2.1 起,.NET Core 中的 System.Transactions 实现将不包括对分布式事务的支持,因此不能使用 TransactionScope 或 CommittableTransaction 来跨多个资源管理器协调事务。主要是不依赖windows中的mstsc功能。
  3. 异步方法使用时需要注意:

    在下面的例子中,我们在TransactionScope内部使用await。

    using(varscope=newTransactionScope()){vargroups=awaitContext.ProductGroups.ToListAsync()。ConfigureAwait(false);}

    看起来没有问题,但它会抛出一个 System.InvalidOperationException:``A TransactionScope must be disposed on the same thread that it was created.

    原因是默认情况下TransactionScope不会从一个线程切换到另一个线程。为了解决这个问题,我们必须使用 TransactionScopeAsyncFlowOption.Enabled:

    using(varscope=newTransactionScope(TransactionScopeAsyncFlowOption.Enabled)){vargroups=awaitContext.ProductGroups.ToListAsync()。ConfigureAwait(false);}

    现在应该可以了吧?这取决于下面的情况。

    如果我们使用和不使用TransactionScopeAsyncFlowOption这个选项的时候都使用了相同的数据库连接,并且第一次执行的时候没有使用这个选项,那么我们会得到另一个异常: System.InvalidOperationException:``Connection currently has transaction enlisted. Finish current transaction and retry.

    换句话说,由于第一个访问的原因,第二个会话将会失败。如下代码所示:

    try{using(varscope=newTransactionScope()){// We know this one - System.InvalidOperationException:// TransactionScope必须放在与创建它相同的线程上。vargroups=awaitContext.ProductGroups.ToListAsync().ConfigureAwait(false);}}catch(Exceptione){// error handling}using(varscope=newTransactionScope(TransactionScopeAsyncFlowOption.Enabled)){// Implemented correctly but throws anyways// System.InvalidOperationException:// 当前连接已经被记录。完成当前事务并重试。vargroups=awaitContext.ProductGroups.ToListAsync().ConfigureAwait(false);}

    想象一下,如果第一个调用是在第三方库或您正在使用的框架中完成的,二您不了解其中的代码 - 如果您之前没有看到此错误,那么你讲无从下手来解决这个问题。

转自:http://www.vnfan.com/robin/d/9eb756520852b21e.html

原文地址:https://www.cnblogs.com/yunspider/p/12158659.html

时间: 2024-10-16 19:07:21

【转】TransactionScope事务处理方法介绍及.NET Core中的注意事项的相关文章

【翻译】介绍 ASP.NET Core 中的 Razor Pages

介绍 ASP.NET Core 中的 Razor Pages 原文地址:Introduction to Razor Pages in ASP.NET Core         译文地址:介绍 asp.net core 中的 Razor Pages          翻译:ganqiyin Razor Pages 是 ASP.NET Core MVC 的一个新功能,可以让基于页面的编程方案更容易,更高效. 如果您正在寻找使用 Model-View-Controller 的教程,请参阅ASP.NET

ORACLE PL/SQL 中序列(sequence)的简易使用方法介绍

如果我是C罗 原文 ORACLE PL/SQL 中序列(sequence)的简易使用方法介绍 sequence在ORACLE中应用十分广泛,就是序列号的意思,会自动增加指定变数,如逐次增加1或者2或者其他. 1.创建序列 Create Sequence 你首先要有CREATE SEQUENCE或者CREATE ANY SEQUENCE 权限 CREATE SEQUENCE CUX_DEMO_SEQUENCEMINVALUE 1MAXVALUE 99999999999START WITH 1000

[翻译]在 .NET Core 中的并发编程

原文地址:http://www.dotnetcurry.com/dotnet/1360/concurrent-programming-dotnet-core 今天我们购买的每台电脑都有一个多核心的 CPU,允许它并行执行多个指令.操作系统通过将进程调度到不同的内核来发挥这个结构的优点.然而,还可以通过异步 I/O 操作和并行处理来帮助我们提高单个应用程序的性能.在.NET Core中,任务 (tasks) 是并发编程的主要抽象表述,但还有其他支撑类可以使我们的工作更容易. 并发编程 - 异步 v

玩转ASP.NET Core中的日志组件

玩转ASP.NET Core中的日志组件简介日志组件,作为程序员使用频率最高的组件,给程序员开发调试程序提供了必要的信息.ASP.NET Core中内置了一个通用日志接口ILogger,并实现了多种内置的日志提供器,例如 ConsoleDebugEventSourceEventLogTraceSourceAzure App Service除了内置的日志提供器,ASP.NET Core还支持了多种第三方日志工具,例如 elmah.ioGelfJSNLogKissLog.netLoggrNLogSe

ASP.NET Core 中的 WebSocket 支持(转自MSDN)

本文介绍 ASP.NET Core 中 WebSocket 的入门方法. WebSocket (RFC 6455) 是一个协议,支持通过 TCP 连接建立持久的双向信道. 它用于从快速实时通信中获益的应用,如聊天.仪表板和游戏应用. 如果不明白什么是WebSocket可以参考这篇文章 系统必备 ASP.NET Core 1.1 或更高版本 支持 ASP.NET Core 的任何操作系统: Windows 7/Windows Server 2008 或更高版本 Linux macOS 如果应用在安

linux下常见内存异常查证工具和方法介绍

linux下常见内存异常查证工具和方法介绍 内存异常导致的异常往往很难查证,本文介绍在linux下的各种常见内存异常的查证工具和方法. 1.访问空指针/未初始化指针 这个是最简单的内存异常了,只要能够生成coredump文件,可以快速定位问题代码. 开启coredump 部分环境下默认不会生成coredump,需要运行如下命令:ulimit -c unlimited //unlimited表示不限制coredump文件大小,也可以指定一个最大文件大小. 定制core文件名 默认的coredump

(五).NET Core中过滤器Filter的使用介绍

知识点回顾: 前面几篇文章分别给大家介绍了 (1)Swagger的集成和用法: (2)JWT身份验证的集成和用法: (3)OOM框架AnutoMapper对象映射的用法: 今天给大家介绍过滤器Filter的基本使用: 过滤器有什么作用,在什么场景下适合用到它? 假设一个项目进展到快结束的时候,项目leader为了保证程序的稳定性和可监控和维护性要求将所有的方法加上日志,如果项目比较庞大,方法非常多,那岂不是得费很大得劲来完成这样一件事情.不过不用担心,咋们遇到的问题,伟大的语言设计者早已帮我们想

关于TransactionScope.Complete方法(链接)

相信有些同学会困扰,当我们执行TransactionScope.Complete()方法的时候,是否Transaction被真正提交到数据库了. 对于这一点,MSDN上有这么一段描述: If the TransactionScope object created the transaction initially, the actual work of committing the transaction by the transaction manager occurs after the l

.NET Core中过滤器Filter的使用介绍

过滤器有什么作用,在什么场景下适合用到它? 假设一个项目进展到快结束的时候,项目leader为了保证程序的稳定性和可监控和维护性要求将所有的方法加上日志,如果项目比较庞大,方法非常多,那岂不是得费很大得劲来完成这样一件事情.不过不用担心,咋们遇到的问题,伟大的语言设计者早已帮我们想好了解决办法过滤器,过滤器是一种AOP(面向切面编程)技术的体现,AOP具有松耦合,易扩展,代码可复用的特点. 通常我们在这些场景下如身份验证.日志记录.异常获取等会使用到过滤器 .NET Core中的过滤器生命周期: