1. 程式人生 > >被忽略的Spring3小改進—支援多資料來源的@Transactional事務註解

被忽略的Spring3小改進—支援多資料來源的@Transactional事務註解

問題描述

有個專案在配置Spring事務時,使用了@Transactional註解,但這個專案使用了多個數據源,而事務註解只對第一個起作用,咋辦?

探幽

先回顧一下之前個人習慣使用的 + 配置方式,大致步驟如下:

1)定義與事務管理器對應的事務通知
2)配置需要攔截的方法呼叫切面
3)將切入點連線到相應的事務通知

整個系統的事務,三下配置,一處搞定,相比註解方式,個人覺得更簡單、省力、統一。

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"> <property name="dataSource" ref="dataSource1"> <qualifier value="order"/> </bean> <bean id="transactionManager2" class="org.springframework.jdbc.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource2"> <qualifier value="account"/> </bean>

2、在需要事務的地方,指定“限定符”

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.

在配置檔案中,預設情況下,<tx:annotation-driven>會自動使用名稱為transactionManager的事務管理器。所以,如果定義的事務管理器名稱為transactionManager,那麼就可以直接使用<tx:annotation-driven/>

@Transactional的屬性

這裡寫圖片描述

配置優化

可以自定義一個繫結到特定事務管理器的註解,然後直接使用這個自定義的註解進行標識:

@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Transactional("tran_1")
public @interface CustomerTransactional {

}

在Service程式碼中使用:

...
//使用名為tran_1的事務管理器
@CustomerTransactional
public void addTest(String str){

}
…