深入浅出事务之传播属性(转)

深入浅出事务之传播属性

本文参考《java Transaction design strategies》

大部分时候,我们都习惯了spring容器默认的配置,但有时候,我们需要知道更多……

当使用声明式事务模型时,您必须告诉容器如何去管理事务,例如,何时开启一个事务?哪些方法需要事务?当前不存在事务的情况下,容器是否需要为其添加事务控制?事实上,Spring提供了一个bean —— TransactionAttributSource,通过配置其事务(传播)属性(transaction attribute)来达到精确控制事务行为的目的。事务的属性总共有六种:

  • Required
  • Mandato
  • RequiresNew
  • Supports
  • NotSupported
  • Never


Spring又添加了一种新的事务属性,PROPAGATION_NESTED,用于实现真正的嵌套事务,前提条件是外部环境必须提供相应的实现支持。尽管可以通过配置的方式在bean(类)级别指定事务属性,一般来说,还是应该将事务属性应用于方法级别。为整个bean配置某个事务属性意味着其内部所有的方法都采用它,而方法级别的事务属性可以将其覆盖。

REQUIRED
Required属性告诉容器某个特定的方法需要一个事务,如果上下文中已经存在事务,则加入;否则,开启一个事务。这是一种使用最频繁的事务属性,适用于大多数情况;但是,并不绝对,下面我们将会看到对于某些场景,总会有更好的理由去使用Mandatory属性。

MANDATORY
Mandatory属性告诉容器某个特定的方法需要一个事务。但是,不同于Required属性,它无论如何都不会开启新的事务;相反的,它会 “强制”要求该方法被调用时上下文中必须存在事务,否则会抛出TransactionRequiredException异常,提示需要一个事务但没有找到。何时选择Mandatory,后面将会专门抽出一节来分析。

REQUIRESNEW
RequiresNew属性告诉容器某个特定的方法需要一个新事务的支持。如果上下文中已经存在事务A,则该事务A挂起,并启动一个新的事务B。当事务B结束后,事务A被唤醒并继续执行。事实上,使用RequiresNew违反了事务的ACID原则,因为新事务会导致原有事务的挂起。
该属性在某个行为必须被完成(提交或回滚)而不受外部事务结果影响时十分有用,例如记录日志。大多数交易系统的每一个操作都必须写进日志,无论其执行结果如何(成功或失败)。假设某个股票交易的方法placement()启动了一个事务,并且调用了一个通用的方法audit()来记录日志。由于 audit()和placement()处于同一个事务的管辖范围之内,因此一旦placement()回滚,audit()记录的日志也会相应的进行回滚;这就违背了“任何成功或失败的操作都必须记录日志”这一业务逻辑。这个时候,如果将audit()的事务属性设作RequiresNew,则确保了 audit()在一个新的、单独的事务中记录日志,因此不受placement()中外部事务的影响。

SUPPORTS
Supports属性告诉容器,该方法不需要事务支持,但如果当前上下文中已经存在了一个事务,则加入其中。Supports这是一个相当强大、相当有用的事务属性。考虑这样一个场景,业务方法A用来查询某个交易者特定时期的交易总量。由于是查询操作,因此这个时候事务并不是必须的,因此我们将其事务属性设为Supports,来告诉容器在调用方法时不要开启新的事务。但是,如果方法A被某个已经存在事务控制的方法B所调用,那么它就会加入当前事务;那么,在该事务提交之前,方法B中对数据的任何修改对于方法A来说,都是可见的。
下面我们举个更具体的例子来说明Supports的作用。假设某位交易者一天的最大交易额是一百万,如果采用Supports作为事务属性,一次超额交易的具体处理流程如下:

  • 目前为止,当天总共的交易量是900,000
  • 事务启动
  • 交易者又进行了一笔200,000的交易
  • 调用事务属性为Supports的查询方法,因为是同一个事务,因此得到结果为1,100,000
  • 业务逻辑判断,已经超过最大交易限额,抛出异常,事务回滚



如果使用NotSupported会发生什么呢?我们不会得到任何异常,因为查询方法不会加入当前事务,因此它看不见当前事务中对数据库的任何修改。

  • 目前为止,当天总共的交易量是900,000
  • 事务启动
  • 交易者又进行了一笔200,000的交易
  • 调用事务属性为SNotupported的查询方法,因为不属于当前事务,因此得到结果为900,000
  • 业务逻辑判断,没有超过最大交易限额,事务提交(实际已超过当天限额)



NotSupported
NotSupported属性告诉容器,该方法不需要事务支持;如果当前上下文中已经存在事务,则该事务被挂起直到该方法执行完毕。如果当前上下文中不存在事务,该方法则在没有事务支持的环境下执行。NotSupported适用于“某些方法在事务控制下有较大可能性会产生异常”的场合。例如在 XA架构的事务处理过程中,调用包含DDL语句的存储过程往往会抛出异常,因此比较好的做法是将其设为NotSupported,暂时挂起当前事务。

Never
Never属性告诉容器,该方法必须在无事务的上下文中运行。注意,这与NotSupported不同,后者意味着,如果上下文中存在事务,则将该事务暂时挂起并在无事务的上下文中运行。但Never却不同,如果当前上下文中已经存在事务,则在调用该方法时会抛出一个异常,提示该方法不能在事务环境下运行。因为使用Never会导致各种意料之外的运行时异常,因此除非必要,一般不推荐使用

Required vs. Mandatory
Required和Mandatory是两个往往容易被混淆的事务属性。两者都可以运行在事务上下文环境中,但当上下文中不存在事务时,Required会自己开启一个事务,而Mandatory则不会。大多数情况下,你可以采用如下的“最佳实践”来区分何时需要哪种策略:如果某一方法需要运行在具备事务的环境,但其本身又不负责事务的控制(回滚),则该方法应该标志为Mandatory。可以看出,上述最佳实践是基于事务的所有权而得来的。

Nested vs. RequiresNew vs. Required
另外两个比较容易的事务属性是Spring提供的Nested与RequiresNew。如果当前上下文中存在事务,两者都是启动一个新的事务;如果当前上下文中不存在事务,则类似于PROPAGATION_REQUIRED,两者也都新建一个事务。那么,它们有什么区别呢?
PROPAGATION_REQUIRES_NEW 启动一个新的, 不依赖于环境的 "内部" 事务. 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等。当内部事务开始执行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执行。

另一方面, PROPAGATION_NESTED 开始一个 "嵌套的" 事务,  它是已经存在事务的一个真正的子事务。嵌套事务开始执行时,  它将取得一个 savepoint。如果这个嵌套事务失败, 我们将回滚到此 savepoint。嵌套事务是外部事务的一部分, 只有外部事务结束后它才会被提交。
总结一下,使用嵌套事务的场景总共有两个,如下图所示:



 

  • 需要事务BC与事务AD一起提交,即:作为事务AD的子事务,事务BC只有在事务AD成功提交时(阶段3成功)才提交。这个需求简单称之为“联合提交”。这一点PROPAGATION_REQUIRED可以做到。
  • 需要事务BC的回滚不会影响事务AD的提交。这个需求简单称之为“隔离回滚”。这一点,可以通过设置事务属性为PROPAGATION_REQUIRES_NEW做到。



使用PROPAGATION_REQUIRED满足需求1,但子事务BC的rollback会迫使父事务AD也回滚,不能满足需求2。使用 PROPAGATION_REQUIRES_NEW满足需求2,但子事务(严格意义上说,这时不应该称之为子事务)BC是一个全新的事务,父事务(严格意义上说,这时也不应该称之为父事务)AD的成功与否完全不影响BC的提交,不能满足需求1。

同时满足上述两条需求就要用到PROPAGATION_NESTED了。PROPAGATION_NESTED在事务AD执行到B点时,设置了 savePoint。当BC事务成功提交时,PROPAGATION_NESTED的行为与PROPAGATION_REQUIRED一样。只有当事务 AD在D点成功提交时,事务BC才真正提交; 如果阶段3执行异常,导致事务AD 回滚,事务BC也将一起回滚,从而满足了“联合提交”。当阶段2执行异常,导致BC事务rollback时,因为设置了savePoint的缘故,AD事务可以选择与BC一起rollback或继续阶段3的执行并保留阶段1的执行结果,从而满足了“隔离回滚”。例如,可以把执行BC事务的方法try-catch起来,在catch中选择是否继续向上抛出异常(是,则回滚到A处;否,则回滚到B处)。而是用PROPAGATION_REQUIRED时,即使try-catch住BC的异常,AD事务也一定会被无条件rollback。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
08-10
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值