JavaEE应用的传统事务有两种策略:全局事务和局部事务。
全局事务由应用服务器管理,需要底层服务器的JTA支持。
局部事务和底层所采用的持久化技术有关,当采用JDBC持久化技术时,需要使用Connection对象来操作事务;而采用Hibernate持久化技术时,需要使用Session对象来操作事务。
当采用传统的事务编程策略时,程序代码必然和具体的事务操作代码耦合,这样造成的后果是:当应用需要在不同的事务策略之间切换时,开发者必须手动修改程序代码。当使用Spring事务策略后,就可以改变这种状况。
Spring事务策略是通过PlatformTransactionManager接口实现的,该接口是Spring事务策略的核心。该接口的源代码如下:
public interface PlatformTransactionManager {
//平台无关的获得事务的方法
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
//平台无关的事务提交方法
void commit(TransactionStatus status) throws TransactionException;
//平台无关的事务回滚方法
void rollback(TransactionStatus status) throws TransactionException;
}
PlatformTransactionManager是一个与任何事务策略分离的接口,随着底层不同事务策略的切换,应用必须采用不同的实现类。PlatformTransactionManager接口没有与任何事务资源捆绑在一起,它可以适应于任何的事务策略,结合Spring的IOC容器,可以向PlatformTransactionManager注入相关的平台特性。
PlatformTransactionManager接口有许多不同的实现类,应用程序面向于平台无关的接口编程,当底层采用不同的持久层技术时,系统只需使用不同的
PlatformTransactionManager实现类即可。而这种切换通常由Spring容器负责管理,应用程序既无须与具体的事务API耦合,也无须与特定实现类耦合,从而将应用和持久化技术、事务API彻底分离开来。
TransactionStatus对象表示一个事务。getTransaction(TransactionDefinition definition)返回的TransactionStatus对象,可能是一个新的事务,也可能是一个已经存在的事务对象;否则,系统将新建一个事务对象后返回。
TransactionDefinition接口定义了一个事务规则,该接口必须指定如下几个属性:
属性 | 说明 |
事务隔离 | 当前事务和其他事务的隔离程度。例如这个事务能否看到其他事务未提交的数据等。 |
事务传播 | 通常,在事务中执行的代码都会在当前事务中运行。但是如果一个事务上下文已经存在,有几个选项可指定该事务性方法的执行行为。例如,大多数情况下,简单地在现有的事务上下文中运行;或者挂起现有事务,创建一个新的事务。Spring提供EJB CMT中所有的事务传播选项。 |
事务超时 | 事务在超时前能运行多久,也就是事务的最长持续时间。如果事务一直没有被提交或回滚,将在超出该时间后,系统自动回滚事务。 |
只读状态 | 只读事务不修改任何数据。在某些情况下,例如使用Hibernate时,只读事务是非常有用的优化。 |
public interface TransactionStatus extends SavepointManager {
boolean isNewTransaction();
boolean hasSavepoint();
void setRollbackOnly();
boolean isRollbackOnly();
boolean isCompleted();
}
public interface SavepointManager {
Object createSavepoint() throws TransactionException;
void rollbackToSavepoint(Object savepoint) throws TransactionException;
void releaseSavepoint(Object savepoint) throws TransactionException;
}
Spring具体的事务管理由PlatformTransactionManager的不同实现类来完成。在Spring容器中配置PlatformTransactionManager Bean时,必须针对不同环境提供不同的实现类。
譬如针对 JDBC数据源 的局部事务策略的配置文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<!-- 定义数据源Bean,使用C3P0数据源实现 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="oracle.jdbc.driver.OracleDriver"/>
<property name="jdbcUrl" value="jdbc:oracle:thin:@localhost:1521:orcl"/>
<property name="user" value="scott"/>
<property name="password" value="tiger"/>
<property name="maxPoolSize" value="40"/>
<property name="minPoolSize" value="1"/>
<property name="initialPoolSize" value="1"/>
<property name="maxIdleTime" value="20"/>
</bean>
<!-- 配置JDBC数据源的局部事务管理器,使用DataSourceTransactionManager类 -->
<!-- 该类实现PlatformTransactionManager接口,是针对采用数据源连接的特定实现 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
针对 Hibernate 的局部事务策略的配置文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<!-- 定义数据源Bean,使用C3P0数据源实现 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="oracle.jdbc.driver.OracleDriver"/>
<property name="jdbcUrl" value="jdbc:oracle:thin:@localhost:1521:orcl"/>
<property name="user" value="scott"/>
<property name="password" value="tiger"/>
<property name="maxPoolSize" value="40"/>
<property name="minPoolSize" value="1"/>
<property name="initialPoolSize" value="1"/>
<property name="maxIdleTime" value="20"/>
</bean>
<!-- 定义Hibernate的SessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources">
<list>
<value>lee/Xxx.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<!-- 配置Hibernate的局部事务管理器,使用HibernateTransactionManager类 -->
<!-- 该类实现PlatformTransactionManager接口,是针对采用Hibernate的特定实现 -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
</beans>
从上面的配置文件可以看出,当采用Spring事务管理策略时,应用程序无须与具体的事务策略耦合。Spring提供了两种事务管理方式:
① 编程式事务管理:即使利用Spring编程式事务时,程序也可直接获取容器中的transactionManager Bean,该Bean总是PlatformTransactionManager的实例,所以可以通过该接口提供的3个方法来开始、提交事务和回滚事务。
② 声明式事务管理:无须在Java程序中书写任何的事务操作代码,而是通过在XML文件中为业务组件配置事务代理,AOP为事务代理所织入的增强处理也由Spring提供:在目标方法执行之前,织入开始事务;在目标方法执行之后,织入结束事务。
不论采用何种持久化策略,Spring都提供了一致的事务抽象,因此,应用开发者能在任何环境下,使用一致的编程模型。无须更改代码,应用就可在不同的事务管理策略中切换。