摘要
Spring框架是一个流行的基于轻量级控Ò 46;反转容器的Java/J2EE应用框架,尤其在数& #25454;访问和事务管理方面的能力是众 2;周知的。Spring的声明性事务分离可以ò 12;用到任何POJO目标对象,并且包含所੍ 7;EJB基于容器管理事务中的已声明事务 。后台的事务管理器支持简单的基É 10;JDBC的事务和全功能的基于JTA的J2EE事务。 ;
这篇文章详细的讨论了Spring的事务管ĩ 02;特性。重点是如何在使用JTA作为后台 ;事务策略的基础上让POJO利用Spring的声明&# 24615;事务,这也显示了Spring的事务服务可& #20197;无缝地与J2EE服务器(如BEA WebLogic Server的事务协调器)的事务协调器进行 ;交互,作为EJB CMT传统事务分离方式的一个替代者。
POJO的声明性事务
作为Spring声明性事务分离方式的样例ʌ 92;让我们来看一下Spring的样例应用PetClinic的 0013;心服务外观中的配置:
清单1:
他遵循Spring的标准XMLBean定义格式。定义ߚ 2;:
1、一个DataSource引用,指向一个JNDI位置—ß 12;J2EE服务器管理下这将从JNDI环境中获取&# 29305;定的DataSource。
2、一个应用服务实现—这是一个POJO, ;封装了业务和数据访问逻辑。在这% 324;实现了应用中的Clinic服务接口。
3、一个应用服务的事务代理—这个 0195;理为目标服务定义了事务属性,匹 配特定的方法名模式并为之创建相ò 12;的事务。在实际的事务管理中,代&# 29702;指向一个PlatformTransactionManager实现。
注意 :除了显式的代理定义A 292;Spring还支持自动代理机制和通过Commons Attributes或J2SE 5.0注解实现源程序级的元数据使用。&# 36825;些可选方法的讨论超过了本文的范 ;围。可以参考Spring的文档来了解相关ಭ 4;节。
业务接口和业务实现是特定于应用 0340;并且不需要关心Spring或者Spring的事务管 702;。普通Java对象可以作为服务的目标ë 45;象,而且任何普通Java接口可以作为 1;务的接口。下面是一个Clinic接口的示Ë 63;:
清单2:
这个接口的实现如下显示,假设他 0351;用JDBC来执行必要的数据访问。他通$ 807;bean属性的设置方法来获取JDBC的DataSource;这ߎ 2;上面的配置中的dataSource属性定义相对应& #12290;
清单3:
如你所见,代码相当直接。我们使 9992;一个简单的Java对象,而事务管理由 107;务代理来处理,这个我们会在下面& #35752;论。
注意在PetClinic示例应用中实际的基于JDBC 0;Clinic实现利用了Spring的JDBC支持类来避免直 5509;使用JDBC的API。虽然Spring的事务管理也可 0197;与普通的基于JDBC实现一起工作,就 521;上面的示例。
定义事务代理
除了JdbcClinic实例以外,配置中也定义了& #19968;个事务代理。如果愿意这个代理 2;暴露的实际接口也可以显式定义。 0664;认情况下,所有由目标对象实现的 接口都暴露出来,在这个例子中就ą 59;应用的Clinic服务接口。
从客户端的观点来看,"clinic" bean只是这个应用的Clinic接口的实现。客 5143;端不需要知道这会被一个事务代理 所处理。这就是接口的能力:一个İ 52;接的目标对象的引用可以容易的被&# 19968;个实现相同接口的代理所代替—在 这儿就是一个隐式创建事务的代理z 90;
代理的具体事务行为会由为根据特 3450;的方法或方法命名模式而定义的事 务属性来驱动,就像下面的例子所Ķ 34;:
清单3:
Key属性决定代理将为方法提供什么样 的事务行为。这个属性的最重要部Ñ 98;就是事务传播行为。下面是一些可&# 36873;的属性值:
1、PROPAGATION_REQUIRED -- 支持当前的事务,如果不存在就创ó 14;一个新的。这是最常用的选择。
2、PROPAGATION_SUPPORTS -- 支持当前的事务,如果不存在就不Ë 51;用事务。
3、PROPAGATION_MANDATORY -- 支持当前的事务,如果不存在就抛Ñ 86;异常。
4、PROPAGATION_REQUIRES_NEW -- 创建一个新的事务,并暂停当前的É 07;务(如果存在)。
5、PROPAGATION_NOT_SUPPORTED -- 不使用事务,并暂停当前的事务(å 14;果存在)。
6、PROPAGATION_NEVER -- 不使用事务,如果当前存在事务就ü 43;出异常。
7、PROPAGATION_NESTED -- 如果当前存在事务就作为嵌入事务û 91;行,否则与PROPAGATION_REQUIRED类似。
前6个事务策略与EJB的CMT类似,而且使 992;相同的常量名,因此对EJB开发人员 9;说是很亲切的。第7个策略PROPAGATION_NESTED是Spring&# 25552;供的一个变体:他需要事务管理器 ;(如DataSourceTransactionManager) 提供类似JDBC3.0那样的保存点API来嵌套事 1153;行为或者通过
JTA支持嵌套事务。
事务属性中的readOnly标识指示相应的事 1153;应该作为一个只读事务来优化。这 是一个优化提示:一些事务策略在Ű 25;种情况下可以得到很好的性能优化&# 65292;如使用ORM工具如Hibernate或TopLink时避免脏数 454;检查(“flush”尝试)。
在事务属性中还有一个“timeout”选项 9;定义事务的超时秒数。在JTA中,这个 属性会简单地传递给J2EE服务器的事务& #21327;调器并被正确地解释。
使用事务代理
在运行时,客户端会取得一个“clinic&rdquo ;引用并转换为Clinic接口,然后调用如loadPe t或storePet方法。这就隐式地使用了Spring的ߚ 7;务代理,通过“事务解释器”在目Ċ 31;对象中注册;这样一个新的事务就&# 21019;建了,然后具体的工作就会代理给 ;JdbcClinic的目标方法。
图1示例了一个使用“建议链”并到$ 798;最后目标的AOP代理的潜在概念。在 5;个示例中,唯一的建议是一个事务 5299;释器用来包装目标方法的事务行为 。这是一种用来在声明性事务功能Ç 79;使用的基于代理的AOP。
Figure 1. An AOP proxy with an advisor chain and a target at the end
例如,一个PetClinic应用的WEB层组件可以执 ;行ServletContext定位来获取Spring WebApplicationContext的引用并且获取受管理的“clinic&rd quo;BEAN:
清单4:
在调用storePet() 之前,Spring的事务代理隐式地创建一个 ;事务。当storePet() 调用返回时,事务将提交或回滚。Ņ 70;省情况下任何RuntimeException或Error将导致回滚z 90;实际的提交或回滚可以是可以定义&# 30340;:Spring的事务属性支持“回滚规则” 0340;概念。
例如,我们可以可以引入一个强制 0340;PetClinicException并且告诉事务代理在抛出异६ 0;时回滚:
清单5:
这儿也有一个类似的“提交规则”Ŧ 21;法,指示特定的异常将触发一次提&# 20132;。
注意上面示例的显式定位引用的方 7861;只是一种访问受Spring管理BEAN的方法的ࡢ 4;化,可以用在任何WEB资源如servlet或filter。 2312;构建基于Spring自身的MVC框架时,BEAN可以 0452;接被注射到WEB控制器中。当然也支ý 45;在如Struts, WebWork, JSF, and Tapestry框架中访问Spring管理BEAN。详情可以参 2771;Spring的文档。
PlatformTransactionManager策略
Spring事务支持的核心接口是org.springframework.transaction.Platf ormTransactionManager。所有Spring的事务分离功能都会&# 22996;托给PlatformTransactionManager(传给相应的TransactionDefinition实 例)来做实际的事务执行。虽然PlatformTrans actionManager接口可以直接调用,但通常应用 只需要配置一个具体的事务管理器ñ 82;且通过声明性事务来分离事务。
Spring提供几种不同的PlatformTransactionManager实现,分 0026;如下两个类别:
1、本地事务策略—支持单一资源的 0107;务(通常是单个数据库),其包括 org.springframework.jdbc.datasource.DataSourceTransactionManager和 org.springframework.orm.hibernate.HibernateTransactionManager。
2、全局事务管理—支持可能跨越多 0010;资源的全局事务。其相应的类为org.spri ngframework.transaction.jta.JtaTransactionManager,将事务委托给遵循JTA& #35268;范的事务协调器(通常为J2EE服务器&# 65292;但不是强制的)。
PlatformTransactionManager抽象的主要价值在于应用不& #20877;被绑定在特定的事务管理环境。 6;反,事务策略可以很容易地切换—$ 890;过选择不同的PlatformTransactionManager实现类。这就 ;使得应用代码与声明事务分离保持 968;致,而不需要考虑应用组件所使用& #30340;环境了。
例如,应用的初始版本可能布署在Tom cat上,与单个Oracle数据库交互。这可以 041;便地利用Spring的事务分离特性,只要 6873;择基于JDBC的DataSourceTransactionManager作为使用的事务 策略。Spring会分离事务,而JDBC驱动会执 4892;相应的原始JDBC事务。
相同应用的另一个版本可能会布署 2312;WebLogic服务器上,使用两个Oracle数据库。&# 24212;用代码和事务分离不需要改变。唯 ;一不同的是选择作为JtaTransactionManager事务策略 ;,让Spring来分离事务而WebLogic服务器的事ࡃ 3;协调器来执行事务。
JTA UserTransaction与JTA TransactionManager比较
让我们来看一下Spring对JTA支持的细节。&# 34429;然并非经常需要考虑这个细节但了 ;解相关的细节还有必要的。对简单 340;用例如前面章节的示例,标准的JtaTransa ctionManager定义已经足够了,
缺省的Spring JtaTransactionManager设置会从标准JNDI位置(J2EE规范所 定义的java:comp/UserTransaction)获取JTA的javax.transaction.UserTransaction对 象。这对大部分标准J2EE环境来说已经& #36275;够了。
然而,缺省的JtaTransactionManager不能执行事务ੀ 2;停(也就是说不支持PROPAGATION_REQUIRES_NEW和PROPAGATION_NOT_SUP PORTED)。原因就在于标准的JTA UserTransaction接口不支持事务的暂停和恢复ᦁ 2;而只支持开始和完成新的事务。
为了实现事务的暂停,需要一个javax.trans action.TransactionManager实例,他提供了JTA定义的标准& #30340;暂停和恢复方法。不幸的是,J2EE没&# 26377;为JTA TransactionManager定义标准的JNDI位置!因此,我们 ;需要使用厂商自己的定位机制。
清单6:
J2EE本质上没有考虑将JTA TransactionManager接口作为公共API的一部分。JTA规ŏ 39;自身定义了将TransactionManager接口作为容器集 成的想法。虽然这是可以理解的,Ê 94;是JTA TransactionManager的标准JNDI位置还是可以增加一定 ;的价值,特别是对轻量级容器如Spring,Ű 25;样任何J2EE服务器就可以用统一的方ঁ 5;来定位JTA TransactionManager了。
不仅Spring的JtaTransactionManager可以从访问中获益, O/R映射工具如Hibernate, Apache OJB, and Kodo JDO也能得到好处,因为他们需要在JTA环 ;境中执行缓存同步的能力(释放缓 384;意味着JTA事务的完成)。这种注册ߚ 7;务同步的能力只有JTA TransactionManager接口才能提供,而UserTransaction是处理 981;了的。因此,这些工具都需要实现& #33258;己的TransactionManager定位器。
为JTA TransactionManager定义标准的JNDI位置是许多底层软 ;件供应商最期望J2EE实现的功能。如果 J2EE5.0的规范制定团队能够认识到这个୲ 5;性的重要性就太好了。幸运地是, 9640;级J2EE服务器如WebLogic Server已经考虑将JTA TransactionManager作为公共的API包含在扩展功能中 。
在WebLogic JTA中实现Spring的事务分离
在WebLogic Server中,JTA TransactionManager官方的JNDI位置定义为javax.transaction.TransactionManager 2290;这个值可以在Spring的JtaTransactionManager中作为“transa ctionManagerName”使用。原则上这样就可以在WebLog ic"s JTA系统中实现事务暂停了,也就是说&# 25903;持PROPAGATION_REQUIRES_NEW和PROPAGATION_NOT_SUPPORTED行为。
除了标准的JtaTransactionManager和其支持的通用ງ 7;置选项外,Spring还提供了一个专用的WebLo gicJtaTransactionManager适配器来直接利用WebLogic的JTA扩展&# 12290;
在享受自动探测WebLogic的JTA TransactionManager的便利之外,他提供超越标准JTA 的三个重要特性:
1、事务命名—暴露出Spring的事务名给WebLo gic Server,使得Spring事务在WebLogic的事务监听器可& #35265;。缺省的,Spring会使用声明性事务的 完整方法名。
2、每事务隔离级别—将Spring事务属性È 13;定义的隔离级别应用到WebLogic JTA事务中。这使得每个事务都可以定&# 20041;数据库的隔离级别,而这是标准JTA 152;不支持的。
3、强制事务恢复—即使在暂停的事 1153;被标识为回滚时也可以恢复。这需 要使用WebLogic的扩展TransactionManager接口来调用forceResume ()方法。
Figure 2. WebLogic Server"s transaction monitor (click the image for a full-size screen shot)
Spring的WebLogicJtaTransactionManager有效地为基于Spring的应用&# 25552;供了WebLogic Server事务管理的全部功能。这使得Spring事& #21153;分离成为一种能与EJB CMT竟争的产品,而且提供了相同级别&# 30340;事务支持。
Spring and EJB CMT
如上所示,Spring的POJO声明性事务分离可& #20197;作为一种除传统EJB CMT这外的选择。但是Spring与EJB并不是完成& #20114;斥的,Spring的应用上下文也可以作为 EJB façade的后台来管理数据访问(DAO)和& #20854;他细纹理的业务对象。
在EJB情景中,事务是由EJB CMT来驱动的。对Spring来说,数据访问支 345;特性会自动检测到这样的环境并且& #37319;用相应的事务。例如,Spring对Hibernate的支 ;持能够提供隐式的资源管理,即使 159;EJB驱动的事务,甚至可以在不需要߾ 2;改任何DAO代码的情况下提供相同的语 义。
Spring有效的解耦了DAO实现与实际的运行&# 29615;境。DAO可以参与Spring的事务就像参与EJB CMT事务一样。这不仅简化在其他环境&# 20013;的重用,而且更方便在J2EE容器外进 4892;测试。
结论
Spring框架为J2EE和非J2EE环境提供了全量的É 07;务分离的特性,特别表现在POJO的声 6;性事务上。他用一种灵活而非侵入 4335;的方式为非EJB环境中的事务分离提Ë 79;了便利。与EJB不同,这样的事务性POJO 4212;用对象可以很容易的被测试和在J2EE 481;器外补重用。
Spring提供了各种事务策略,如JtaTransactionManager是 用来代理J2EE服务器的事务协调器,而J DBC DataSourceTransactionManager是用来为简单的JDBC DataSource(就是单一目标数据库)执行事 1153;。Spring可以很容易为不同的环境通过&# 21518;台配置的简单修改来调整事务策略 ;。
超越标准的JTA支持,Spring为WebLogic Server的JTA扩展提供了完善的集成,可以 903;持高级特性如事务监视和每事务隔& #31163;级别。通过对WebLogic Server的特殊支持,基于Spring的应用可以完& #20840;利用WebLogic Server的事务管理功能。
Spring事务分离是继EJB CMT之外的另一种可选方式,特别是对&# 37027;些基于POJO的轻量级架构。在那只是 2240;为选择LSSB(本地无状态会话BEAN)来应 用声明性事务的情况下,基于Spring的POJO 6381;务模型是一种可行的选择,他提供 了非常高层的灵活性、可测试性和ŵ 25;用性。
资源
JTA - The JTA specification JTA规范
WebLogic JTA - Documentation of WebLogic"s JTA extensions WebLogicJTA扩展文档
关于作者
Juergen Hoeller是Spring框架的创始人之一
Spring框架是一个流行的基于轻量级控Ò 46;反转容器的Java/J2EE应用框架,尤其在数& #25454;访问和事务管理方面的能力是众 2;周知的。Spring的声明性事务分离可以ò 12;用到任何POJO目标对象,并且包含所੍ 7;EJB基于容器管理事务中的已声明事务 。后台的事务管理器支持简单的基É 10;JDBC的事务和全功能的基于JTA的J2EE事务。 ;
这篇文章详细的讨论了Spring的事务管ĩ 02;特性。重点是如何在使用JTA作为后台 ;事务策略的基础上让POJO利用Spring的声明&# 24615;事务,这也显示了Spring的事务服务可& #20197;无缝地与J2EE服务器(如BEA WebLogic Server的事务协调器)的事务协调器进行 ;交互,作为EJB CMT传统事务分离方式的一个替代者。
POJO的声明性事务
作为Spring声明性事务分离方式的样例ʌ 92;让我们来看一下Spring的样例应用PetClinic的 0013;心服务外观中的配置:
清单1:
<bean id="dataSource"><br> class="org.springframework.jndi.JndiObjectFactoryBean"><br><br><br><property name="jndiName"><br><value>java:comp/env/jdbc/petclinic</value><br></property><br></bean>
<bean id="transactionManager"><br> class="org.springframework.transaction.jta.JtaTransactionManager"/><br><br><bean id="clinicTarget"><br> class="org.springframework.samples.petclinic.jdbc.JdbcClinic"><br><property name="dataSource"><ref bean="dataSource"></ref><br></property><br><br><bean id="clinic"><br> class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"><br><property name="transactionManager"><ref bean="transactionManager"></ref><br><property name="target"><ref bean="clinicTarget"></ref><br><property name="transactionAttributes"><br><props><br><prop key="load*">PROPAGATION_REQUIRED,readOnly</prop><br><prop key="store*">PROPAGATION_REQUIRED</prop><br></props><br></property><br></property></property></bean></bean></bean>
他遵循Spring的标准XMLBean定义格式。定义ߚ 2;:
1、一个DataSource引用,指向一个JNDI位置—ß 12;J2EE服务器管理下这将从JNDI环境中获取&# 29305;定的DataSource。
2、一个应用服务实现—这是一个POJO, ;封装了业务和数据访问逻辑。在这% 324;实现了应用中的Clinic服务接口。
3、一个应用服务的事务代理—这个 0195;理为目标服务定义了事务属性,匹 配特定的方法名模式并为之创建相ò 12;的事务。在实际的事务管理中,代&# 29702;指向一个PlatformTransactionManager实现。
注意 :除了显式的代理定义A 292;Spring还支持自动代理机制和通过Commons Attributes或J2SE 5.0注解实现源程序级的元数据使用。&# 36825;些可选方法的讨论超过了本文的范 ;围。可以参考Spring的文档来了解相关ಭ 4;节。
业务接口和业务实现是特定于应用 0340;并且不需要关心Spring或者Spring的事务管 702;。普通Java对象可以作为服务的目标ë 45;象,而且任何普通Java接口可以作为 1;务的接口。下面是一个Clinic接口的示Ë 63;:
清单2:
public interface Clinic {
Pet loadPet(int id);
void storePet(Pet pet);
...
}
这个接口的实现如下显示,假设他 0351;用JDBC来执行必要的数据访问。他通$ 807;bean属性的设置方法来获取JDBC的DataSource;这ߎ 2;上面的配置中的dataSource属性定义相对应& #12290;
清单3:
public class JdbcClinic implements
Clinic {
private DataSource dataSource;
public void
setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public Pet loadPet(int id) {
try {
Connection con =
this.dataSource.getConnection();
...
}
catch (SQLException ex) {
...
}
}
public void storePet(Pet pet) {
try {
Connection con =
this.dataSource.getConnection();
...
}
catch (SQLException ex) {
...
}
}
...
}
如你所见,代码相当直接。我们使 9992;一个简单的Java对象,而事务管理由 107;务代理来处理,这个我们会在下面& #35752;论。
注意在PetClinic示例应用中实际的基于JDBC 0;Clinic实现利用了Spring的JDBC支持类来避免直 5509;使用JDBC的API。虽然Spring的事务管理也可 0197;与普通的基于JDBC实现一起工作,就 521;上面的示例。
定义事务代理
除了JdbcClinic实例以外,配置中也定义了& #19968;个事务代理。如果愿意这个代理 2;暴露的实际接口也可以显式定义。 0664;认情况下,所有由目标对象实现的 接口都暴露出来,在这个例子中就ą 59;应用的Clinic服务接口。
从客户端的观点来看,"clinic" bean只是这个应用的Clinic接口的实现。客 5143;端不需要知道这会被一个事务代理 所处理。这就是接口的能力:一个İ 52;接的目标对象的引用可以容易的被&# 19968;个实现相同接口的代理所代替—在 这儿就是一个隐式创建事务的代理z 90;
代理的具体事务行为会由为根据特 3450;的方法或方法命名模式而定义的事 务属性来驱动,就像下面的例子所Ķ 34;:
清单3:
<prop key="load*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="store*">PROPAGATION_REQUIRED</prop>
Key属性决定代理将为方法提供什么样 的事务行为。这个属性的最重要部Ñ 98;就是事务传播行为。下面是一些可&# 36873;的属性值:
1、PROPAGATION_REQUIRED -- 支持当前的事务,如果不存在就创ó 14;一个新的。这是最常用的选择。
2、PROPAGATION_SUPPORTS -- 支持当前的事务,如果不存在就不Ë 51;用事务。
3、PROPAGATION_MANDATORY -- 支持当前的事务,如果不存在就抛Ñ 86;异常。
4、PROPAGATION_REQUIRES_NEW -- 创建一个新的事务,并暂停当前的É 07;务(如果存在)。
5、PROPAGATION_NOT_SUPPORTED -- 不使用事务,并暂停当前的事务(å 14;果存在)。
6、PROPAGATION_NEVER -- 不使用事务,如果当前存在事务就ü 43;出异常。
7、PROPAGATION_NESTED -- 如果当前存在事务就作为嵌入事务û 91;行,否则与PROPAGATION_REQUIRED类似。
前6个事务策略与EJB的CMT类似,而且使 992;相同的常量名,因此对EJB开发人员 9;说是很亲切的。第7个策略PROPAGATION_NESTED是Spring&# 25552;供的一个变体:他需要事务管理器 ;(如DataSourceTransactionManager) 提供类似JDBC3.0那样的保存点API来嵌套事 1153;行为或者通过
JTA支持嵌套事务。
事务属性中的readOnly标识指示相应的事 1153;应该作为一个只读事务来优化。这 是一个优化提示:一些事务策略在Ű 25;种情况下可以得到很好的性能优化&# 65292;如使用ORM工具如Hibernate或TopLink时避免脏数 454;检查(“flush”尝试)。
在事务属性中还有一个“timeout”选项 9;定义事务的超时秒数。在JTA中,这个 属性会简单地传递给J2EE服务器的事务& #21327;调器并被正确地解释。
使用事务代理
在运行时,客户端会取得一个“clinic&rdquo ;引用并转换为Clinic接口,然后调用如loadPe t或storePet方法。这就隐式地使用了Spring的ߚ 7;务代理,通过“事务解释器”在目Ċ 31;对象中注册;这样一个新的事务就&# 21019;建了,然后具体的工作就会代理给 ;JdbcClinic的目标方法。
图1示例了一个使用“建议链”并到$ 798;最后目标的AOP代理的潜在概念。在 5;个示例中,唯一的建议是一个事务 5299;释器用来包装目标方法的事务行为 。这是一种用来在声明性事务功能Ç 79;使用的基于代理的AOP。
Figure 1. An AOP proxy with an advisor chain and a target at the end
例如,一个PetClinic应用的WEB层组件可以执 ;行ServletContext定位来获取Spring WebApplicationContext的引用并且获取受管理的“clinic&rd quo;BEAN:
清单4:
WebApplicationContext ctx
=
WebApplicationContexUtils.getWebApplicationContext(servletContext);
Clinic clinic = (Clinic)
ctx.getBean("clinic);
Pet pet = new Pet();
pet.setName("my new cat");
clinic.storePet(pet);
在调用storePet() 之前,Spring的事务代理隐式地创建一个 ;事务。当storePet() 调用返回时,事务将提交或回滚。Ņ 70;省情况下任何RuntimeException或Error将导致回滚z 90;实际的提交或回滚可以是可以定义&# 30340;:Spring的事务属性支持“回滚规则” 0340;概念。
例如,我们可以可以引入一个强制 0340;PetClinicException并且告诉事务代理在抛出异६ 0;时回滚:
清单5:
<prop key="load*">PROPAGATION_REQUIRED,readOnly,-PetClinicException</prop>
<prop key="store*">PROPAGATION_REQUIRED,-PetClinicException</prop>
这儿也有一个类似的“提交规则”Ŧ 21;法,指示特定的异常将触发一次提&# 20132;。
注意上面示例的显式定位引用的方 7861;只是一种访问受Spring管理BEAN的方法的ࡢ 4;化,可以用在任何WEB资源如servlet或filter。 2312;构建基于Spring自身的MVC框架时,BEAN可以 0452;接被注射到WEB控制器中。当然也支ý 45;在如Struts, WebWork, JSF, and Tapestry框架中访问Spring管理BEAN。详情可以参 2771;Spring的文档。
PlatformTransactionManager策略
Spring事务支持的核心接口是org.springframework.transaction.Platf ormTransactionManager。所有Spring的事务分离功能都会&# 22996;托给PlatformTransactionManager(传给相应的TransactionDefinition实 例)来做实际的事务执行。虽然PlatformTrans actionManager接口可以直接调用,但通常应用 只需要配置一个具体的事务管理器ñ 82;且通过声明性事务来分离事务。
Spring提供几种不同的PlatformTransactionManager实现,分 0026;如下两个类别:
1、本地事务策略—支持单一资源的 0107;务(通常是单个数据库),其包括 org.springframework.jdbc.datasource.DataSourceTransactionManager和 org.springframework.orm.hibernate.HibernateTransactionManager。
2、全局事务管理—支持可能跨越多 0010;资源的全局事务。其相应的类为org.spri ngframework.transaction.jta.JtaTransactionManager,将事务委托给遵循JTA& #35268;范的事务协调器(通常为J2EE服务器&# 65292;但不是强制的)。
PlatformTransactionManager抽象的主要价值在于应用不& #20877;被绑定在特定的事务管理环境。 6;反,事务策略可以很容易地切换—$ 890;过选择不同的PlatformTransactionManager实现类。这就 ;使得应用代码与声明事务分离保持 968;致,而不需要考虑应用组件所使用& #30340;环境了。
例如,应用的初始版本可能布署在Tom cat上,与单个Oracle数据库交互。这可以 041;便地利用Spring的事务分离特性,只要 6873;择基于JDBC的DataSourceTransactionManager作为使用的事务 策略。Spring会分离事务,而JDBC驱动会执 4892;相应的原始JDBC事务。
相同应用的另一个版本可能会布署 2312;WebLogic服务器上,使用两个Oracle数据库。&# 24212;用代码和事务分离不需要改变。唯 ;一不同的是选择作为JtaTransactionManager事务策略 ;,让Spring来分离事务而WebLogic服务器的事ࡃ 3;协调器来执行事务。
JTA UserTransaction与JTA TransactionManager比较
让我们来看一下Spring对JTA支持的细节。&# 34429;然并非经常需要考虑这个细节但了 ;解相关的细节还有必要的。对简单 340;用例如前面章节的示例,标准的JtaTransa ctionManager定义已经足够了,
缺省的Spring JtaTransactionManager设置会从标准JNDI位置(J2EE规范所 定义的java:comp/UserTransaction)获取JTA的javax.transaction.UserTransaction对 象。这对大部分标准J2EE环境来说已经& #36275;够了。
然而,缺省的JtaTransactionManager不能执行事务ੀ 2;停(也就是说不支持PROPAGATION_REQUIRES_NEW和PROPAGATION_NOT_SUP PORTED)。原因就在于标准的JTA UserTransaction接口不支持事务的暂停和恢复ᦁ 2;而只支持开始和完成新的事务。
为了实现事务的暂停,需要一个javax.trans action.TransactionManager实例,他提供了JTA定义的标准& #30340;暂停和恢复方法。不幸的是,J2EE没&# 26377;为JTA TransactionManager定义标准的JNDI位置!因此,我们 ;需要使用厂商自己的定位机制。
清单6:
<bean id="transactionManager"><br> class="org.springframework.transaction.jta.JtaTransactionManager"><br><br><br><property name="transactionManagerName"><br><value>vendorSpecificJndiLocation</value><br></property><br></bean>
J2EE本质上没有考虑将JTA TransactionManager接口作为公共API的一部分。JTA规ŏ 39;自身定义了将TransactionManager接口作为容器集 成的想法。虽然这是可以理解的,Ê 94;是JTA TransactionManager的标准JNDI位置还是可以增加一定 ;的价值,特别是对轻量级容器如Spring,Ű 25;样任何J2EE服务器就可以用统一的方ঁ 5;来定位JTA TransactionManager了。
不仅Spring的JtaTransactionManager可以从访问中获益, O/R映射工具如Hibernate, Apache OJB, and Kodo JDO也能得到好处,因为他们需要在JTA环 ;境中执行缓存同步的能力(释放缓 384;意味着JTA事务的完成)。这种注册ߚ 7;务同步的能力只有JTA TransactionManager接口才能提供,而UserTransaction是处理 981;了的。因此,这些工具都需要实现& #33258;己的TransactionManager定位器。
为JTA TransactionManager定义标准的JNDI位置是许多底层软 ;件供应商最期望J2EE实现的功能。如果 J2EE5.0的规范制定团队能够认识到这个୲ 5;性的重要性就太好了。幸运地是, 9640;级J2EE服务器如WebLogic Server已经考虑将JTA TransactionManager作为公共的API包含在扩展功能中 。
在WebLogic JTA中实现Spring的事务分离
在WebLogic Server中,JTA TransactionManager官方的JNDI位置定义为javax.transaction.TransactionManager 2290;这个值可以在Spring的JtaTransactionManager中作为“transa ctionManagerName”使用。原则上这样就可以在WebLog ic"s JTA系统中实现事务暂停了,也就是说&# 25903;持PROPAGATION_REQUIRES_NEW和PROPAGATION_NOT_SUPPORTED行为。
除了标准的JtaTransactionManager和其支持的通用ງ 7;置选项外,Spring还提供了一个专用的WebLo gicJtaTransactionManager适配器来直接利用WebLogic的JTA扩展&# 12290;
在享受自动探测WebLogic的JTA TransactionManager的便利之外,他提供超越标准JTA 的三个重要特性:
1、事务命名—暴露出Spring的事务名给WebLo gic Server,使得Spring事务在WebLogic的事务监听器可& #35265;。缺省的,Spring会使用声明性事务的 完整方法名。
2、每事务隔离级别—将Spring事务属性È 13;定义的隔离级别应用到WebLogic JTA事务中。这使得每个事务都可以定&# 20041;数据库的隔离级别,而这是标准JTA 152;不支持的。
3、强制事务恢复—即使在暂停的事 1153;被标识为回滚时也可以恢复。这需 要使用WebLogic的扩展TransactionManager接口来调用forceResume ()方法。
Figure 2. WebLogic Server"s transaction monitor (click the image for a full-size screen shot)
Spring的WebLogicJtaTransactionManager有效地为基于Spring的应用&# 25552;供了WebLogic Server事务管理的全部功能。这使得Spring事& #21153;分离成为一种能与EJB CMT竟争的产品,而且提供了相同级别&# 30340;事务支持。
Spring and EJB CMT
如上所示,Spring的POJO声明性事务分离可& #20197;作为一种除传统EJB CMT这外的选择。但是Spring与EJB并不是完成& #20114;斥的,Spring的应用上下文也可以作为 EJB façade的后台来管理数据访问(DAO)和& #20854;他细纹理的业务对象。
在EJB情景中,事务是由EJB CMT来驱动的。对Spring来说,数据访问支 345;特性会自动检测到这样的环境并且& #37319;用相应的事务。例如,Spring对Hibernate的支 ;持能够提供隐式的资源管理,即使 159;EJB驱动的事务,甚至可以在不需要߾ 2;改任何DAO代码的情况下提供相同的语 义。
Spring有效的解耦了DAO实现与实际的运行&# 29615;境。DAO可以参与Spring的事务就像参与EJB CMT事务一样。这不仅简化在其他环境&# 20013;的重用,而且更方便在J2EE容器外进 4892;测试。
结论
Spring框架为J2EE和非J2EE环境提供了全量的É 07;务分离的特性,特别表现在POJO的声 6;性事务上。他用一种灵活而非侵入 4335;的方式为非EJB环境中的事务分离提Ë 79;了便利。与EJB不同,这样的事务性POJO 4212;用对象可以很容易的被测试和在J2EE 481;器外补重用。
Spring提供了各种事务策略,如JtaTransactionManager是 用来代理J2EE服务器的事务协调器,而J DBC DataSourceTransactionManager是用来为简单的JDBC DataSource(就是单一目标数据库)执行事 1153;。Spring可以很容易为不同的环境通过&# 21518;台配置的简单修改来调整事务策略 ;。
超越标准的JTA支持,Spring为WebLogic Server的JTA扩展提供了完善的集成,可以 903;持高级特性如事务监视和每事务隔& #31163;级别。通过对WebLogic Server的特殊支持,基于Spring的应用可以完& #20840;利用WebLogic Server的事务管理功能。
Spring事务分离是继EJB CMT之外的另一种可选方式,特别是对&# 37027;些基于POJO的轻量级架构。在那只是 2240;为选择LSSB(本地无状态会话BEAN)来应 用声明性事务的情况下,基于Spring的POJO 6381;务模型是一种可行的选择,他提供 了非常高层的灵活性、可测试性和ŵ 25;用性。
资源
JTA - The JTA specification JTA规范
WebLogic JTA - Documentation of WebLogic"s JTA extensions WebLogicJTA扩展文档
关于作者
Juergen Hoeller是Spring框架的创始人之一