难经7:被忽略的Spring3小改进——支持多数据源的@Transactional事务注解
liuu.iteye.com
2011-3-23
[问题]
近日,有同事问起,有个项目在配置Spring事务时,使用了@Transactional注解,但这个项目使用了多个数据源,而事务注解只对第一个起作用,咋办?
[探幽]
一听之下,想起在用@Transactional配置事务时,确实没注意过多数据源问题,但是记得之前常用的XML配置方式中,对多数据源支持很简单,我想注解配置起来应该也不会太麻烦。
先回顾一下之前个人习惯使用的 <tx:advice> + <aop:config>配置方式,大致步骤如下:
1)定义与事务管理器对应的事务通知
2)配置需要拦截的方法调用切面
3)将切入点连接到相应的事务通知
整个系统的事务,三下配置,一处搞定,相比注解方式,个人觉得更简单、省力、统一;而要支持多数据源,再做一遍这123即可,非常简单。
不过同事在网上百度了一圈,说大部分的结论是Spring的@Transactional注解不支持,听到这一点我很诧异,不应该啊,要不查查Spring的官方文档?
一查马上发现,在Spring3.0的参考文档中,针对这个问题的,真新增了一节(10.5.6.2)来解决,参见:
(http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/transaction.html#transaction-declarative-annotations )
Most Spring applications only need a single transaction manager, but there may be situations where you want multiple independent transaction managers in a single application. The value attribute of the
@Transactional annotation can be used to optionally specify the identity of the
PlatformTransactionManager to be used. This can either be the bean name or the qualifier value
of the transaction manager bean
也就是说,在Spring2.5之前,@Transactional注解确实不支持多数据源,但是Spring3为其增加了value属性配置,可以指定当前事务通知对应的事务管理器。
检查了一下Spring的changelogs,这个特性是在3.0M4版中加入的:
@Transactional supports qualifier value for choosing between multiple transaction managers
[解难]
看来,或许这是一个有用的小改进,但很可能被大家忽略了。下面是从官方文档中摘抄出来的示例配置方式,供需要的同学参考:
1、配置事务注解驱动、每个数据源对应的事务管理器,并定义“限定符”
- <tx:annotation-driven/>
- <bean id="transactionManager1" class="org.springframework.jdbc.DataSourceTransactionManager">
- ...
- <qualifier value="order"/>
- </bean>
- <bean id="transactionManager2" class="org.springframework.jdbc.DataSourceTransactionManager">
- ...
- <qualifier value="account"/>
- </bean>
2、在需要事务的地方,指定“限定符”
- public class TransactionalService {
- @Transactional("order")
- public void setSomething(String name) { ... }
- @Transactional("account")
- public void doSomething() { ... }
- }
public class TransactionalService {
@Transactional("order")
public void setSomething(String name) { ... }
@Transactional("account")
public void doSomething() { ... }
}
3、如果不指定“限定符”,将默认使用“transationManager”命名对应的事务管理器
- The default <tx:annotation-driven> target bean name transactionManager will still be used if no specifically qualified PlatformTransactionManager bean is found
The default <tx:annotation-driven> target bean name transactionManager will still be used if no specifically qualified PlatformTransactionManager bean is found
呼呼,小改进,大作用啊。