8.6 Spring的事务 8.6.1 Spring支持的事务策略

8.6 Spring的事务

Spring的事务管理不需要与任何特定的事务API耦合。对不同的持久层访问技术,编程式事务提供了一致的事务编程风格,通过模板化操作一致性地管理事务。声明式事务基于Spring AOP实现,但并不需要开发者真正精通AOP技术,亦可容易地使用Spring的声明式事务管理。

8.6.1 Spring支持的事务策略

Java EE应用的传统事务有两种策略:全局事务局部事务

  • 全局事务由应用服务器管理,需要底层服务器的JTA支持。

  • 局部事务和底层所采用的持久化技术有关,

    • 当采用JDBC持久化技术时,需要使用Connection对象来操作事务;
    • 而采用Hibernate持久化技术时,需要使用Session对象来操作事务。
  • 全局事务可以跨多个事务性资源(典型例子是关系数据库和消息队列);

  • 使用局部事务,应用服务器不需要参与事务管理,因此不能保证跨多个事务性资源的事务的正确性。

当然,实际上大部分应用都使用单一的事务性资源。
图8.18对比了JTA全局事务、JDBC局部事务、 Hibernate事务的事务操作代码。
这里有一张图片
从图8.18可以看岀,当采用传统的事务编程策略时,程序代码必然和具体的事务操作代码耦合,这样造成的后果是:当应用需要在不同的事务策略之间切换时,开发者必须手动修改程序代码。如果使用Spring事务管理策略,就可以改变这种现状。

PlatformTransactionManager接口

Spring事务策略是通过PlatformTransactionManager接口体现的,该接口是Spring事务策略的核心。该接口的源代码如下:

1
2
3
4
5
6
7
8
9
public interface PlatformTransactionManager
{
//平台无关的获得事务的方法
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
//平台无关的事务提交方法
void commit(TransactionStatus status) throws TransactionException;
//平台无关的事务回滚方法
void rollback(TransactionStatus status) throws TransactionException;
}

PlatformTransactionManager是一个与任何事务策略分离的接口,随着底层不同事务策略的切换,应用必须采用不同的实现类。 PlatformTransactioManager接口没有与任何事务性资源捆绑在一起,它可以适应于任何的事务策略,结合SpringloC容器,可以向PlatformTransactionManager注入相关的平台特性。
Platform Transaction Manager接口有许多不同的实现类,应用程序面向与平台无关的接口编程,当底层采用不同的持久层技术时,系统只需使用不同的PlatformTransactionManager实现类即可—而这种切换通常由Spring容器负责管理,应用程序既无须与具体的事务API耦合,也无须与特定实现类耦合,从而将应用和持久化技术、事务API彻底分离开来
Spring的事务机制是一种典型的策略模式, PlatformTransactionManager代表事务管理接口,但它并不知道底层到底如何管理事务,它只要求事务管理需要提供开始事务( getTransaction())、提交事务( commit())和回滚事务( rollback())三个方法,但具体如何实现则交给其实现类来完成——不同的实现类则代表不同的事务管理策略。
即使使用容器管理的JTA,代码也依然无须执行JNDI查找,无须与特定的JTA资源耦合在一起通过配置文件,JTA资源传给PlatformTransactionManager的实现类。因此,程序的代码可在JTA事务管理和非JTA事务管理之间轻松切换。

Spring本身没有任何事务支持,它只是负责包装底层的事务,应用程序面向PlatformTransactionManager接口编程时, Spring在底层负责将这些操作转换成具体的事务操作代码,因此应用的底层支持怎样的事务策略,那么Spring就可支持怎样的事务策略。 Spring事务管理的优势是将应用从具体的事务API中分离出来,而不是真正提供事务管理的底层实现。

PlatformTransactionManager接口内,包含一个getTransaction(TransactionDefinition definition)方法,该方法根据TransactionDefinition参数返回一个TransactionStatus对象。 TransactionStatus对象表示一个事务, TransactionStatus被关联在当前执行的线程上。
getTransaction(Transaction Definition definitio)返回的TransactionStatus对象,可能是一个新的事务,也可能是一个已经存在的事务对象。如果当前执行的线程已经处于事务管理下,则返回当前线程的事务对象;否则,系统将新建一个事务对象后返回。

TransactionDefinition接口

TransactionDefinition接口定义了一个事务规则,该接口必须指定如下几个属性值。

  1. 事务隔离:当前事务和其他事务的隔离程度。例如,这个事务能否看到其他事务未提交的数据
  2. 事务传播:通常,在事务中执行的代码都会在当前事务中运行。但是,如果一个事务上下文已经存在,有几个选项可指定该事务性方法的执行行为。例如,在大多数情况下,简单地在现有的事务上下文中运行;或者挂起现有事务,创建一个新的事务。 Spring提供EJB CMT( ContainManagerTransaction,容器管理事务)中所有的事务传播选项。
  3. 事务超时:事务在超时前能运行多久,也就是事务的最长持续时间。如果事务一直没有被提交或回滚,将在超出该时间后,系统自动回滚事务。
  4. 只读状态:只读事务不修改任何数据。在某些情况下(例如使用Hibernate时),只读事务是非常有用的优化。

TransactionStatus接口

TransactionStatus代表事务本身,它提供了简单的控制事务执行和查询事务状态的方法,这些方法在所有的事务API中都是相同的。 TransactionStatus接口的源代码如下:

1
2
3
4
5
6
7
8
9
public interface TransactionStatus
{
//判断事务是否为新建的事务
boolean isNewTransaction();
//设置事务回滚
void setRollbackOnly();
//查询事务是否已有回滚标志
boolean isRollbackOnly();
}

Spring具体的事务管理由PlatformTransactionManager的不同实现类来完成。在Spring容器中配置PlatformTransactionManager Bean时,必须针对不同的环境提供不同的实现类。

程序示例

下面提供了不同的持久层访问环境及其对应的PlatformTransactionManager实现类的配置。

JDBC数据源配置示例

JDBC数据源的局部事务管理器的配置文件如下:

JTA配置示例

容器管理的JTA全局事务管理器的配置文件如下:

从上面的配置文件来看,当配置JtaTransactionManager全局事务管理策略时,只需指定事务管理器实现类即可,无须传入额外的事务性资源。这是因为全局事务的JTA资源由Java EE服务器提供,而Spring容器能自行从Java EE服务器中获取该事务性资源,所以无须使用依赖注入来配置。

Hibernate配置示例

当采用Hibernate持久层访问策略时,局部事务策略的配置文件如下:

如果底层采用Hibernate持久层技术,但事务采用JTA全局事务,则Spring配置文件如下:

从上面的配置文件可以看出,不论采用哪种持久层访问技术,只要使用JTA全局事务, Spring事务管理的配置就完全一样,因为它们采用的都是全局事务管理策略。
当采用JTA全局事务策略时,实际上需要底层应用服务器的支持,而不同应用服务器所提供的JTA全局事务可能存在细节上的差异,因此实际配置全局事务管理器时可能需要使用JtaTransactionManager的子类,如WebLogicJtaTransactionManager(Orcale提供的WebLogic)WebSphereUowTransactionManager(IBM提供的WebSphere)等,它们分别对应于不同的应用服务器
从上面的配置文件可以看出,当应用程序采用Spring事务管理策略时,应用程序无须与具体的事务策略耦合,应用程序只要面向PlatformTransactionManager策略接口编程, ApplicationContext将会根据配置文件选择合适的事务策略实现类。

实际上, Spring提供了如下两种事务管理方式。

  1. 编程式事务管理:即使使用Spring的编程式事务,程序也可直接获取容器中的transactionManager Bean,该Bean总是PlatformTransactionManager的实例,所以可以通过该接口提供的三个方法来开始事务、提交事务和回滚事务。
  2. 声明式事务管理:无须在Java程序中书写任何事务操作代码,而是通过在XML文件中为业务组件配置事务代理(AOP代理的一种),AOP为事务代理所织入的增强处理也由Spring提供—在目标方法执行之前,织入开始事务;在目标方法执行之后,织入结束事务

不论采用何种持久化策略, Spring都提供了一致的事务抽象,因此,应用开发者能在仼何环境下使用一致的编程模型。无须更改代码,应用就可在不同的事务管理策略中切换。
当使用编程式事务时,开发者使用的是Spring事务抽象(面向PlatformTransactionManager接口编程),而无须使用任何具体的底层事务APISpring的事务管理将代码从底层具体的事务API中抽象出来,该抽象能以任何底层事务为基础。

提示:Spring的编程式事务还可通过TransactionTemplate类来完成,该类提供了一个execute(TransactionCallback action)方法,可以以更简捷的方式来进行事务操作.

当使用声明式事务时,开发者无须书写任何事务管理代码,不依赖Spring或仼何其他事务APISpring的声明式事务无须任何额外的容器支持, Spring容器本身管理声明式事务。使用声明式事务策略,可以让开发者更好地专注于业务逻辑的实现。

Spring所支持的事务策略非常灵活, Spring的事务策略允许应用程序在不冋的事务策略之间自由切换,即使需要在局部事务策略和全局事务策略之间切换,也只需要修改配置文件即可,而应用程序的代码无须任何改变。这种灵活的设计,正是面向接口编程带来的优势.