2015第24周三Spring事务3

在一个典型的事务处理场景中,有以下几个参与者:

Resource Manager(RM)

ResourceManager简称RM,它负责存储并管理系统数据资源的状态,比如数据库服务器,JMS消息服务器等都是相应的Resource Manager。

Transaction Processing Monitor(TP Monitor)

Transaction Processing Monitor简称TPM或者TP Monitor,它的职责是在分布式事务场景中协调包含多个RM的事务处理。TP Monitor通常对应特定的软件中间件(Middleware), 随着软件开发技术的进步,TP Monitor的实现也由原来基于过程式的设计与实现转向面向对象的更趋模块化的设计和实现。J2EE规范[4]中的应用服务器(Application Server)通常担当的就是TP Monitor的角色。

Transaction Manager(TM)

Transaction Manager简称为TM,它可以认为是TP Monitor中的核心模块,直接负责多RM之间的事务处理的协调工作,并且提供事务界定(Transaction Demarcation)[5], 事务上下文传播(transaction context propagation)[6]等功能接口。

Application

以独立形式存在的或者运行于容器中的应用程序,可以认为是事务边界的触发点。

实际上,并非每一个事务的场景中都会出现以上提到的所有参与者,如果我们根据整个事务中牵扯的RM的多寡来区分事务类型的话,可以将事务分为两类,即全局事务(Global Transaction)和局部事务(Local Transaction),在这两类事务中,具体的事务参与者是不同的.

局部事务与全局事务的主要区分在于“事务”中牵扯多少RM,而不是“系统”中实际有多少RM,这是需要我们注意的地方。 即使你系统中存在多个数据库(即RM),只要你当前事务只更新一个数据库的数据,那当前事务就依然应该算作局部事务,而不是全局事务(虽然这种情况下,你也可以启用全局事务)。

实际上,针对单一事务资源的事务管理,你可以在局部事务中直接使用RM内置的事务支持来进行,你也可以引入TP Monitor在分布式事务场景中进行,通常情况下, 各TP Monitor在实现的时候会检测参与事务的RM数目,如果只有单一的RM参与,TP Monitor会做一定的优化,避免采用“两阶段提交”协议的负担, 但即使如此,针对单一事务资源参与的事务,直接采用局部事务中RM内置的事务支持,无论是从复杂度,还是从效率上来看,都要更胜一筹。

在Java的局部事务场景中,系统中事务管理的具体处理方式会随着所使用的数据访问技术的不同而各异,我们不是使用专用的事务API来管理事务, 而是通过当前使用的数据访问技术所提供的基于“connection” [7] 的API来管理事务。

Java平台上的分布式事务管理主要是通过Java Transaction API(JTA)或者Java Connector Architecture(JCA)提供支持的。

JTA是Sun提出的标准化分布式事务访问的Java接口规范。不过,JTA规范定义的只是一套Java接口定义,具体的实现留给了相应的提供商去实现,各JavaEE应用服务器需要提供对JTA的支持, 另外,除了可以使用绑定到各JavaEE应用服务器的JTA实现之外,Java平台上也存在几个独立的并且比较成熟的JTA实现产品,这包括:

使用JTA进行分布式事务管理通常有两种方式,直接使用JTA接口的编程事务管理以及基于应用服务器的声明性事务管理。

spring的事务框架将开发过程中事务管理相关的关注点进行适当的分离,并对这些关注点进行合理的抽象,最终打造了一套使用方便却功能强大的事务管理“利器”。 通过spring的事务框架,我们可以按照统一的编程模型来进行事务编程,却不用关心所使用的数据访问技术以及具体要访问什么类型的事务资源; 并且,spring的事务框架与spring提供的数据访问支持可以紧密结合,更是让你在事务管理与数据访问之间游刃有余,而最主要的,结合spring的AOP框架, spring的事务框架为我们带来了只有CMT才有的使用声明式事务管理的待遇,却无需绑定到任何的应用服务器上。

spring的事务抽象包括三个主要接口,即PlatformTransactionManager,TransactionDefinition以及TransactionStatus,三接口以org.springframework.transaction.PlatformTransactionManager为中心,org.springframework.transaction.PlatformTransactionManager负责界定事务边界,org.springframework.transaction.TransactionDefinition负责定义事务相关属性,包括隔离级别,传播行为等, org.springframework.transaction.PlatformTransactionManager将参照org.springframework.transaction.TransactionDefinition的属性定义来开启相关事务,事务开启之后到事务结束期间的事务状态由org.springframework.transaction.TransactionStatus负责, 我们也可以通过org.springframework.transaction.TransactionStatus对事务进行有限的控制。

TransactionDefinition针对事务的传播行为提供了以下几种选择,除了PROPAGATION_NESTED是spring特有的外,其他的传播行为的语义与CMT基本相同:

  • PROPAGATION_REQUIRED.  如果当前存在一个事务,则加入当前事务;如果不存在任何事务,则创建一个新的事务。总之,要至少保证在一个事务中运行。PROPAGATION_REQUIRED通常作为默认的事务传播行为。

  • PROPAGATION_SUPPORTS.  如果当前存在一个事务,则加入当前事务;如果当前不存在事务,则直接执行。 对于一些查询方法来说,PROPAGATION_SUPPORTS通常是比较合适的传播行为选择。 如果当前方法直接执行,那么不需要事务的支持;如果当前方法被其他方法调用,而其他方法启动了一个事务的时候,使用PROPAGATION_SUPPORTS可以保证当前方法能够加入当前事务并洞察当前事务对数据资源所做的更新。 比如说,A.service()会首先更新数据库,然后调用B.service()进行查询,那么,B.service()如果是PROPAGATION_SUPPORTS的传播行为, 就可以读取A.service()之前所做的最新更新结果,而如果使用稍后所提到的PROPAGATION_NOT_SUPPORTED,则B.service()将无法读取最新的更新结果,因为A.service()的事务在这个时候还没有提交(除非隔离级别是read uncommitted):

  • PROPAGATION_MANDATORY.  PROPAGATION_MANDATORY强制要求当前存在一个事务,如果不存在,则抛出异常。 如果某个方法需要事务支持,但自身又不管理事务提交或者回滚的时候,比较适合使用PROPAGATION_MANDATORY。 你可以参照《JAVA TRANSACTION DESIGN STRATEGIES》一书中对REQUIRED和MANDATORY两种传播行为的比较来更深入的了解PROPAGATION_MANDATORY的可能应用场景。

  • PROPAGATION_REQUIRES_NEW.  不管当前是否存在事务,都会创建新的事务。如果当前存在事务的话,会将当前的事务挂起(suspend)。 如果某个业务对象所做的事情不想影响到外层事务的话,PROPAGATION_REQUIRES_NEW应该是合适的选择,比如,假设当前的业务方法需要向数据库中更新某些日志信息, 但即使这些日志信息更新失败,我们也不想因为该业务方法的事务回滚而影响到外层事务的成功提交,因为这种情况下,当前业务方法的事务成功与否对外层事务来说是无关紧要的。

  • PROPAGATION_NOT_SUPPORTED.  不支持当前事务,而是在没有事务的情况下执行。如果当前存在事务的话,当前事务原则上将被挂起(suspend),但要依赖于对应的PlatformTransactionManager实现类是否支持事务的挂起(suspend),更多情况请参照TransactionDefinition的javadoc文档。 PROPAGATION_NOT_SUPPORTED与PROPAGATION_SUPPORTS之间的区别,可以参照PROPAGATION_SUPPORTS部分的实例内容。

  • PROPAGATION_NEVER.  永远不需要当前存在事务,如果存在当前事务,则抛出异常。

  • PROPAGATION_NESTED.  如果存在当前事务,则在当前事务的一个嵌套事务中执行,否则与PROPAGATION_REQUIRED的行为类似,即创建新的事务,在新创建的事务中执行。 PROPAGATION_NESTED粗看起来好像与PROPAGATION_REQUIRES_NEW的行为类似,实际上二者是有差别的。 PROPAGATION_REQUIRES_NEW创建的新事务与外层事务属于同一个“档次”,即二者的地位是相同的,当新创建的事务运行的时候,外层事务将被暂时挂起(suspend); 而PROPAGATION_NESTED创建的嵌套事务则不然,它是寄生于当前外层事务的,它的地位比当前外层事务的地位要小一号,当内部嵌套事务运行的时候,外层事务也是出于active状态:

    也就是说,PROPAGATION_REQUIRES_NEW新创建的事务虽然是在当前外层事务内执行,但新创建的事务是独立于当前外层事务而存在的,二者拥有各自独立的状态而互不干扰; 而PROPAGATION_NESTED创建的事务属于当前外层事务的内部子事务(sub-transaction),内部子事务的处理内容属于当前外层事务的一部分,而不能独立于外层事务而存在,并且与外层事务共有事务状态,我想这也就是为什么称其为内部嵌套事务的原因。

    PROPAGATION_NESTED可能的应用场景在于,你可以将一个大的事务划分为多个小的事务来处理,并且外层事务可以根据各个内部嵌套事务的执行结果来选择不同的执行流程。 比如,某个业务对象的业务方法A.service()可能调用其他业务方法B.service()向数据库中插入一批业务数据,但当插入数据的业务方法出现错误的时候(比如主键冲突),我们可以在当前事务中捕捉前一个方法抛出的异常,然后选择另一个更新数据的业务方法C.service()来执行, 这个时候,我们就可以把B.service()和C.serivce()方法的传播行为指定为PROPAGATION_NESTED

    不过,并非所有的PlatformTransactionManager实现都支持PROPAGATION_NESTED类型的传播行为,现在只有org.springframework.jdbc.datasource.DataSourceTransactionManager在使用JDBC3.0数据库驱动的情况下才支持(当然,数据库和相应的驱动程序也需要提供支持),另外, 某些JtaTransactionManager也可能提供支持,但JTA规范并没有要求提供对嵌套事务的支持。

    PlatformTransactionManager是spring事务抽象框架的核心组件,关于它的定义以及作用我们之前已经提过了,所以,这部分我们不妨更多的关注一下PlatformTransactionManager整个的层次体系以及针对不同数据访问技术的实现类。

    PlatformTransactionManager整个的抽象体系基于Strategy模式,由PlatformTransactionManager对事务界定进行统一抽象,而具体的界定策略的实现则交由具体的实现类。 下面我们先来看一下有哪些实现类可供我们使用.

    PlatformTransactionManager的实现类可以划分到面向局部事务和面向全局事务两个分支:

    • 面向局部事务的PlatformTransactionManager实现类.  spring为各种数据访问技术提供了现成的PlatformTransactionManager实现支持,以下列表给出了各种数据访问技术与它们对应的实现类的关系:

      数据访问技术PlatformTransactionManager实现类
      JDBC/iBatis DataSourceTransactionManager
      Hibernate HibernateTransactionManager
      JDO JdoTransactionManager
      JPA(Java Persistence API) JpaTransactionManager
      TopLink TopLinkTransactionManager
      JMS JmsTransactionManager
      JCA Local Transaction CciLocalTransactionManager

      在这些实现类当中,CciLocalTransactionManager可能是比较少见的实现,CCI的意思是Common Client Interface, CciLocalTransactionManager主要是面向JCA的局部事务(Local Transaction),本书不打算对JCA的集成做过多的阐述,读者如果在实际项目中需要使用到JCA进行EIS(Enterprise Information System)系统集成,你可以从spring的参考文档获得使用spring提供的JCA集成支持的足够信息。

      有了这些实现类,我们在使用spring的事务抽象框架进行事务管理的时候,只需要根据当前使用的数据访问技术选择对应的PlatformTransactionManager实现类即可。

    摘自:http://www.cnblogs.com/superjt/archive/2013/05/20/3088847.html

原文地址:https://www.cnblogs.com/doit8791/p/4567803.html