Annotation还是XML的配置方式一直是Java world争论的焦点; 声明式事务管理(Declarative Transaction Management)是现在用的最多的一种事务管理方式。Spring同时提供了Annotation和XML配置方式的声明式事务管理。本文主要讨论这两种方式的各自特点,以及如何选择适当的声明式事务配置方式
声明式事务
自从EJB提出了声明式事务管理的概念,声明式事务管理就成为事务管理的最佳选择。在Spring出来之前,使用声明式事务需要使用符合J2EE规范的应用服务器,例如Weblogic, Websphere等。Spring出来以后,可以通过 AOP非常优雅的实现了声明式事务,而不必需要应用服务器的支持,这也是很多人选择使用Spring的原因。
Spring提供了Annotation风格和XML风格的声明式事务管理。下文将分别讨论这两种方式的优缺点。
从Sping1.x就开始支持的风格,在spirng2.0中同时使用AspectJ风格的AOP更加简化了这种风格的配置。这种方式也是目前使用最多的一种方式。
<beans> <aop:config> <aop:pointcut id="defaultServiceOperation" expression="execution(* x.y.service.*Service.*(..))"/> <aop:advisor pointcut-ref="defaultServiceOperation" advice-ref="defaultTxAdvice"/> <aop:pointcut id="noTxServiceOperation" expression="execution(* x.y.service.ddl.DefaultDdlManager.*(..))"/> <aop:advisor pointcut-ref="noTxServiceOperation" advice-ref="noTxAdvice"/> </aop:config> <!-- this bean will be transactional (c.f. the 'defaultServiceOperation' pointcut) --> <bean id="fooService" class="x.y.service.DefaultFooService"/> <!-- this bean will also be transactional, but with totally different transctional settings --> <bean id="anotherFooService" class="x.y.service.ddl.DefaultDdlManager"/> <tx:advice id="defaultTxAdvice"> <tx:attributes> <tx:method name="get*" read-only="true"/> <tx:method name="*"/> </tx:attributes> </tx:advice> <tx:advice id="noTxAdvice"> <tx:attributes> <tx:method name="*" propagation="NEVER"/> </tx:attributes> </tx:advice> <!-- other transaction infrastructure beans such as a PlatformTransactionManager omitted... --> </beans>
public class A { public m() { //需要事务 a(); //不需要事务,操作时间比较长。 b(); } //需要事务定义 public n() { … } }
Spring2.0开始支持Annotation风格的声明式事务。可以在类或者方法级别声明事务,具体可参考spring手册
public class A { public m() { a(); //不需要事务,操作时间比较长 b(); } @Transactional public n() { … } }
优点: 比较灵活,在一个类中,我可以选择指定哪些方法需要事务。在上一节的例子中,我们就可以在方法 n上声明事务, 而方法m不用声明事务,不用新建一个类。
缺点:事务定义分散在源代码中,没有一个统一的事务切面视图。修改事务定义,需要修改源代码。
在选择XML还是Annotation的问题上,java社区还是有很多争论,Annotation风格越来越受到重视。实际应用中,是一个case by case的问题。在经典的3层体系结构(presentation,service,persistent)中,现在通常会把事务边界定义在业务层,而选择以哪种方式声明事务可以参考以下几点建议: