理解spring声明式事务管理
Spring也提供了声明式事务管理。这是通过Spring AOP实现的。
Spring中进行事务管理的通常方式是利用AOP(面向切片编程)的方式,为普通java类封装事务控制,它是通过动态代理实现的,由于接口是延迟实例化的,spring在这段时间内通过拦截器,加载事务切片。原理就是这样,具体细节请参考jdk中有关动态代理的文档。本文主要讲解如何在spring中进行事务控制。
动态代理的一个重要特征是,它是针对接口的,所以我们的dao要通过动态代理来让spring接管事务,就必须在dao前面抽象出一个接口,当然如果没有这样的接口,那么spring会使用CGLIB来解决问题,但这不是spring推荐的方式,所以不做讨论.
大多数Spring用户选择声明式事务管理。这是最少影响应用代码的选择,因而这是和非侵入性的轻量级容器的观念是一致的。
从考虑EJBCMT和Spring声明式事务管理的相似以及不同之处出发是很有益的。它们的基本方法是相似的:都可以指定事务管理到单独的方法;如果需要可以在事务上下文调用setRollbackOnly()方法。不同之处如下:
不象EJBCMT绑定在JTA上,Spring声明式事务管理可以在任何环境下使用。只需更改配置文件,它就可以和JDBC、JDO、Hibernate或其他的事务机制一起工作
Spring可以使声明式事务管理应用到普通Java对象,不仅仅是特殊的类,如EJB
Spring提供声明式回滚规则:EJB没有对应的特性,我们将在下面讨论这个特性。回滚可以声明式控制,不仅仅是编程式的
Spring允许你通过AOP定制事务行为。例如,如果需要,你可以在事务回滚中插入定制的行为。你也可以增加任意的通知,就象事务通知一样。使用EJBCMT,除了使用setRollbackOnly(),你没有办法能够影响容器的事务管理
Spring不提供高端应用服务器提供的跨越远程调用的事务上下文传播。如果你需要这些特性,我们推荐你使用EJB。然而,不要轻易使用这些特性。通常我们并不希望事务跨越远程调用
回滚规则的概念是很重要的:它们使得我们可以指定哪些异常应该发起自动回滚。我们在配置文件中,而不是Java代码中,以声明的方式指定。因此,虽然我们仍然可以编程调用TransactionStatus对象的setRollbackOnly()方法来回滚当前事务,多数时候我们可以指定规则,如MyApplicationException应该导致回滚。这有显著的优点,业务对象不需要依赖事务基础设施。例如,它们通常不需要引入任何SpringAPI,事务或其他任何东西。
EJB的默认行为是遇到系统异常(通常是运行时异常),EJB容器自动回滚事务。EJBCMT遇到应用程序异常(除了java.rmi.RemoteException外的checked异常)时不会自动回滚事务。虽然Spring声明式事务管理沿用EJB的约定(遇到unchecked异常自动回滚事务),但是这是可以定制的。
按照我们的测试,Spring声明式事务管理的性能要胜过EJBCMT。
通常通过TransactionProxyFactoryBean设置Spring事务代理。我们需要一个目标对象包装在事务代理中。这个目标对象一般是一个普通Java对象的bean。当我们定义TransactionProxyFactoryBean时,必须提供一个相关的PlatformTransactionManager的引用和事务属性。事务属性含有上面描述的事务定义。
<beanid="petStore"class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<propertyname="transactionManager"><refbean="transactionManager"/></property>
<propertyname="target"><refbean="petStoreTarget"/></property>
<propertyname="transactionAttributes"><props><propkey="insert*">PROPAGATION_REQUIRED,-MyCheckedException</prop><propkey="update*">PROPAGATION_REQUIRED</prop><propkey="*">PROPAGATION_REQUIRED,readOnly</prop></props></property></bean>
code]
事务代理会实现目标对象的接口:这里是id为petStoreTarget的bean。(使用CGLIB也可以实现具体类的代理。只要设置proxyTargetClass属性为true就可以。如果目标对象没有实现任何接口,这将自动设置该属性为true。通常,我们希望面向接口而不是类编程。)使用proxyInterfaces属性来限定事务代理来代理指定接口也是可以的(一般来说是个好想法)。也可以通过从org.springframework.aop.framework.ProxyConfig继承或所有AOP代理工厂共享的属性来定制TransactionProxyFactoryBean的行为。
这里的transactionAttributes属性定义在org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource中的属性格式来设置。这个包括通配符的方法名称映射是很直观的。注意insert*的映射的值包括回滚规则。添加的-MyCheckedException指定如果方法抛出MyCheckedException或它的子类,事务将会自动回滚。可以用逗号分隔定义多个回滚规则。-前缀强制回滚,+前缀指定提交(这允许即使抛出unchecked异常时也可以提交事务,当然你自己要明白自己在做什么)。
TransactionProxyFactoryBean允许你通过“preInterceptors”和“postInterceptors”属性设置“前”或“后”通知来提供额外的拦截行为。可以设置任意数量的“前”和“后”通知,它们的类型可以是Advisor(可以包含一个切入点),MethodInterceptor或被当前Spring配置支持的通知类型(例如ThrowAdvice,AfterReturningtAdvice或BeforeAdvice,这些都是默认支持的)。这些通知必须支持实例共享模式。如果你需要高级AOP特性来使用事务,如有状态的maxin,那最好使用通用的org.springframework.aop.framework.ProxyFactoryBean,而不是TransactionProxyFactoryBean实用代理创建者。
也可以设置自动代理:配置AOP框架,不需要单独的代理定义类就可以生成类的代理。
附两个spring的事务配置例子:
<propkey="add">
PROPAGATION_REQUIRES_NEW,-MyException
</prop>
注:上面的意思是add方法将独占一个事务,当事务处理过程中产生MyException异常或者该异常的子类将回滚该事务。
<propkey="loadAll">
PROPAGATION_SUPPORTS,ISOLATION_READ_COMMITED,Readonly
</prop>
注:表示loadAll方法支持事务,而且不会读取没有提交事务的数据。它的数据为只读(这样有助于提高读取的性能)
附ASpring中的所有事务策略
PROPAGATION_MANDATORY
PROPAGATION_NESTED
PROPAGATION_NEVER
PROPAGATION_NOT_SUPPORTED
PROPAGATION_REQUIRED
PROPAGATION_REQUIRED_NEW
PROPAGATION_SUPPORTS
附BSpring中所有的隔离策略:
ISOLATION_DEFAULT
ISOLATION_READ_UNCOMMITED
ISOLATION_COMMITED
ISOLATION_REPEATABLE_READ
ISOLATION_SERIALIZABLE