传统事务有2种策略,全局事务和局部事务。
全局事务:由应用服务器(比如WebLogic或JBoss)管理,需要底层服务器的JTA支持。
局部事务:和底层所采用的持久化技术有关。当采用JDBC持久化技术时,需要使用Connection对象来操作事务;当采用Hibernate持久化技术时,需要使用Session对象来操作事务。
全局事务可以跨多个事务性资源(典型例子是关系数据库和消息队列),使用局部事务,应用服务器不需要参与事务管理,因此不能保证跨多个事务性资源的事务的正确性。当然,实际上大部分的应用都使用单一事务性的资源。
下图是JTA全局事务、JDBC局部事务、Hibernate事务的事务操作代码对比:
从图中可以看出,当采用传统事务编程策略时,程序代码必然和具体的事务操作代码耦合。这样造成的后果是:当应用需要在不同的事务策略之间切换时,开发者必须手动修改程序代码。当使用Spring事务操作策略后,就可以改变这种现状。
二、Spring事务策略
Spring事务策略是通过PlatformTransactionManager接口体现的,该接口是Spring事务策略的核心。该接口的源代码如下:
public interface PlatformTransactionManager { //平台无关的获得事务的方法 public abstract TransactionStatus getTransaction(TransactionDefinition transactiondefinition) throws TransactionException; //平台无关的事务提交方法 public abstract void commit(TransactionStatus transactionstatus) throws TransactionException; //平台无关的事务回滚方法 public abstract void rollback(TransactionStatus transactionstatus) throws TransactionException; }
PlatformTransactionManager是一个与任何事物策略分离的接口,随着底层不同事务策略的切换,应用必须采用不同的实现类。PlatformTransactionManager没有与任何事务资源捆绑在一起,它可以适用于任何的事务策略,结合Spring的IoC容器,可以向PlatformTransactionManager注入相关的平台特性。
PlatformTransactionManager有许多不同的实现类,应用程序面向与接口无关的平台编程,当底层采用不同的持久层技术时,系统只需使用不同的PlatformTransactionManager实现类即可--而这种切换通常由Spring容器负责管理,应用程序既无需与具体的事务API耦合,也无需与特定实现类耦合,从而将应用和持久化技术、事务API彻底分离开来。
Spring具体的事务管理由PlatformTransactionManager的不同实现类来完成。在Spring容器中配置PlatformTransactionManager Bean时,必须针对不同环境提供不同的实现类。
1.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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <!-- 定义数据源bean --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <!-- 指定连接数据库的驱动 --> <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" /> <!-- 指定连接数据库的URL --> <property name="url" value="jdbc:oracle:****" /> <property name="username" value="****" /> <property name="password" value="****" /> <!-- 指定连接数据库连接池的最大连接数 --> <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"> <!-- 需要依赖注入dataSource的引用 --> <property name="dataSource" ref="dataSource" /> </bean> <beans>
2.容器管理的JTA全局事务的配置文件如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <!-- 配置JNDI数据源bean --> <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> <!-- 容器管理数据源的JNDI --> <property name="jndiName" value="jdbc/jpetstore" /> </bean> <!-- 使用JtaTransactionManager,该类实现PlatformTransactionManager接口 --> <!-- 针对采用全局事务管理的特定实现 --> <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" /> <beans>
从上面的配置文件可以看出,当配置JtaTransactionManager全局事务管理策略时,只需指定事务管理器实现类即可,无需传入额外的事务资源。这是因为全局事务JTA资源由应用服务器提供,而Spring容器能自行从服务器中获取该事务资源,所以无需使用依赖注入来配置。
3.当采用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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <!-- 定义数据源bean --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <!-- 指定连接数据库的驱动 --> <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" /> <!-- 指定连接数据库的URL --> <property name="url" value="jdbc:oracle:****" /> <property name="username" value="****" /> <property name="password" value="****" /> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <!-- mappingResources属性用来列出全部映射文件 --> <property name="mappingResources"> <list> <!-- 以下用来列出所有的PO映射文件 --> <value>lee/MyTest.hbm.xml</value> </list> </property> <!-- 定义Hibernate的SessionFactory的属性 --> <property name="hibernateProperties"> <props> <!-- 指定hibernate的连接方言 --> <prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop> <!-- 是否根据hibernate映射创建数据表 --> <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>
如果底层采用Hibernate持久化技术,但事务采用JTA全局事务,则Spring配置文件如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <!-- 配置JNDI数据源bean --> <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> <!-- 容器管理数据源的JNDI --> <property name="jndiName" value="jdbc/jpetstore" /> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <!-- mappingResources属性用来列出全部映射文件 --> <property name="mappingResources"> <list> <!-- 以下用来列出所有的PO映射文件 --> <value>lee/MyTest.hbm.xml</value> </list> </property> <!-- 定义Hibernate的SessionFactory的属性 --> <property name="hibernateProperties"> <props> <!-- 指定hibernate的连接方言 --> <prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop> <!-- 是否根据hibernate映射创建数据表 --> <prop key="hibernate.hbm2ddl.auto">update</prop> </props> </property> </bean> <!-- 使用JtaTransactionManager,该类实现PlatformTransactionManager接口 --> <!-- 针对采用全局事务管理的特定实现 --> <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" /> <beans>
从以上的配置文件可以看出,不论采用哪种持久层访技术,只要使用JTA全局事务,Spring事务管理的配置完全一样。