3.2<wbr></wbr>声明式事务管理
声明式事务管理是通过Spring AOP实现的。
大多数Spring用户选择声明式事务管理。这是最少影响应用代码的选择,因而这是和非侵入性的轻量级容器的观念是一致的。
从考虑EJB CMT和Spring声明式事务管理的相似以及不同之处出发是很有益的。它们的基本方法是相似的:都可以指定事务管理到单独的方法;如果需要可以在事务上下文调用setRollbackOnly()方法。不同之处如下:
·<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>不象EJB CMT绑定在JTA上,Spring声明式事务管理可以在任何环境下使用。只需更改配置文件,它就可以和JDBC、JDO、Hibernate或其他的事务机制一起工作
·<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>Spring可以使声明式事务管理应用到普通Java对象,不仅仅是特殊的类,如EJB
·<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>Spring提供声明式回滚规则:EJB没有对应的特性,我们将在下面讨论这个特性。回滚可以声明式控制,不仅仅是编程式的
·<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>Spring允许你通过AOP定制事务行为。例如,如果需要,你可以在事务回滚中插入定制的行为。你也可以增加任意的通知,就像事务通知一样。使用EJBCMT,除了使用setRollbackOnly(),你没有办法能够影响容器的事务管理
·<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>Spring不提供高端应用服务器提供的跨越远程调用的事务上下文传播。如果你需要这些特性,我们推荐你使用EJB。然而,不要轻易使用这些特性。通常我们并不希望事务跨越远程调用
回滚规则的概念是很重要的:它们使得我们可以指定哪些异常应该发起自动回滚。我们在配置文件中以声明的方式指定。因此,虽然我们仍然可以编程调用TransactionStatus对象的setRollbackOnly()方法来回滚当前事务,多数时候我们可以指定规则,如MyApplicationException应该导致回滚。这有显著的优点,业务对象不需要依赖事务基础设施。例如,它们通常不需要引入任何Spring API,事务或其他任何东西。
EJB的默认行为是遇到系统异常(通常是运行时异常),EJB容器自动回滚事务。EJB CMT遇到应用程序异常(除了java.rmi.RemoteException外的checked异常)时不 会自动回滚事务。虽然Spring声明式事务管理沿用EJB的约定(遇到unchecked 异常自动回滚事务),但是这是可以定制的。
按照我们的测试,Spring声明式事务管理的性能要胜过EJB CMT。
通常通过TransactionProxyFactoryB<wbr>ean</wbr>设置Spring事务代理。我们需要一个目标对象包装在事务代理中。这个目标对象一般是一个普通Java对象的bean。当我们定义TransactionProxyFactoryB<wbr>ean</wbr>时,必须提供一个相关的 PlatformTransactionManag<wbr>er</wbr>的引用和事务属性。事务属性含有上面描述的事务定义。
<>
<wbr><wbr><wbr><wbr> lang="EN-US" style="font-size:9pt"><span style="font-family:宋体"><wbr><wbr><wbr></wbr></wbr></wbr></span></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr></wbr></wbr></wbr>
<wbr><wbr><wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr><wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> PROPAGATION_REQUIRED,-MyCheckedException</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>PROPAGATION_REQUIRED</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> PROPAGATION_REQUIRED,readOnly</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr><wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr></wbr></wbr></wbr>
intPROPAGATION_REQUIRED=0表示当前方法必须运行在事务中。如果调用它的客户在事务中,则当前方法直接使用该事务,否则启新事务。
intPROPAGATION_SUPPORTS=1表示当前方法可以运行在事务中,也可以不运行在事务中。
intPROPAGATION_MANDATORY=2表示当前方法必须运行在事务中。如果调用它的客户不在事务中,则抛出异常。
int PROPAGATION_REQUIRES_NEWS =3表示当前方法必须运行在事务中。无论客户如何,都要启新事务。
int PROPAGATION_NOT_SUPPORTED =4表示当前方法不能运行在事务中。如果客户处于事务中,执行到该业务方法时,事物要挂起。
int PROPAGATION_ NEVER=5表示调用当前方法的客户不能够处于事务中,否则将抛出异常。
int PROPAGATION_NESTED=6 表明当前方法支持事务嵌套。
事务代理会实现目标对象的接口:这里是id为petStoreTarget的bean。(使用 CGLIB也可以实现具体类的代理。只要设置proxyTargetClass属性为true就可以。 如果目标对象没有实现任何接口,这将自动设置该属性为true。通常,我们希望面向接口而不是类编程。)使用proxyInterfaces属性来限定事务代理来代理指定接口也是可以的(一般来说是个好想法)。也可以通过从org.springframework.aop.framework.ProxyConfig继承或所有AOP代理工厂共享的属性来定制TransactionProxyFactoryB<wbr>ean</wbr>的行为。
这里的transactionAttributes属性定义在org.springframework.transaction.interceptor.NameMatchTransactionAttr<wbr>ibuteSource</wbr>中的属性格式来设置。这个包括通配符的方法名称映射是很直观的。拦截器会按照规则拦截业务方法。注意insert*的映射的值包括回滚规则。添加的-MyCheckedException 指定如果方法抛出MyCheckedException或它的子类,事务将会自动回滚。可以用逗号分隔定义多个回滚规则。-前缀强制回滚,+前缀指定提交(这允许即使抛出unchecked异常时也可以提交事务,当然你自己要明白自己在做什么)。
注:insert*表示petStoreTarget业务类中所有以insert开头的业务方法。
<wbr></wbr><wbr></wbr>注:切入点是业务类的方法!拦截器也是拦截到方法!
TransactionProxyFactoryB<wbr>ean</wbr>允许你通过 “preInterceptors”和“postInterceptors”属性设置“前”或“后”通知来提供额外的拦截行为。可以设置任意数量的“前”和“后”通知,它们的类型可以是 Advisor(可以包含一个切入点),MethodInterceptor或被当前Spring配置支持的通知类型 (例如ThrowAdvice, AfterReturningtAdvice或BeforeAdvice,这些都是默认支持的)。这些通知必须支持实例共享模式。如果你需要高级AOP特性来使用事务,如有状态的maxin,那最好使用通用的 org.springframework.aop.framework.ProxyFactoryBean,而不是TransactionProxyFactoryB<wbr>ean</wbr>实用代理创建者。
也可以设置自动代理:配置AOP框架,不需要单独的代理定义类就可以生成类的代理。
ES的架构中,事务是这样实现的:
<!—首先定义一个事务代理的抽象父类-->
"txProxyTemplate" abstract="true"
<wbr><wbr><wbr>lang="EN-US"style="font-size:10pt;background:white;color:blue;font-family:'CourierNew'">"org.springframework.transaction.interceptor.TransactionProxyFactoryB<wbr>ean"</wbr></wbr></wbr></wbr>>
<wbr><wbr><wbr></wbr></wbr></wbr>"transactionManager">"transactionManager"><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr></wbr></wbr></wbr>"transactionAttributes">
<wbr><wbr><wbr></wbr></wbr></wbr>
<wbr><wbr><wbr></wbr></wbr></wbr>"query*">PROPAGATION_REQUIRED,readOnly
<wbr><wbr><wbr></wbr></wbr></wbr>"get*">PROPAGATION_REQUIRED,readOnly
<wbr><wbr><wbr></wbr></wbr></wbr>"*">PROPAGATION_REQUIRED,-com.rubik.es.framework.exception.BaseAppException
<wbr><wbr><wbr></wbr></wbr></wbr>
<wbr><wbr></wbr></wbr>
<!—然后将每个业务接口将这个抽象Bean作为自己的父Bean,这样就继承下来了所有的属性-->
"IBasicManager" parent="txProxyTemplate">
<wbr><wbr><wbr><wbr><wbr><wbr></wbr></wbr></wbr></wbr></wbr></wbr>"target">
<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>"com.rubik.es.logic.basic.impl.BasicManager">
<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>"commonDAO">"commonDAO"/>
<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr><wbr><wbr><wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr></wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr></wbr></wbr>