PlatformTransactionManager


詳見:https://www.cnblogs.com/softidea/p/5877546.html

Spring Boot 使用事務非常簡單,首先使用注解 @EnableTransactionManagement 開啟事務支持后,然后在訪問數據庫的Service方法上添加注解 @Transactional 便可。

關於事務管理器,不管是JPA還是JDBC等都實現自接口 PlatformTransactionManager 如果你添加的是 spring-boot-starter-jdbc 依賴,框架會默認注入 DataSourceTransactionManager 實例。如果你添加的是 spring-boot-starter-data-jpa 依賴,框架會默認注入 JpaTransactionManager 實例。

你可以在啟動類中添加如下方法,Debug測試,就能知道自動注入的是 PlatformTransactionManager 接口的哪個實現類。

@EnableTransactionManagement // 啟注解事務管理,等同於xml配置方式的 <tx:annotation-driven />
@SpringBootApplication
public class ProfiledemoApplication {

    @Bean
    public Object testBean(PlatformTransactionManager platformTransactionManager){
        System.out.println(">>>>>>>>>>" + platformTransactionManager.getClass().getName());
        return new Object();
    }

    public static void main(String[] args) {
        SpringApplication.run(ProfiledemoApplication.class, args);
    }
}

這些SpringBoot為我們自動做了,這些對我們並不透明,如果你項目做的比較大,添加的持久化依賴比較多,我們還是會選擇人為的指定使用哪個事務管理器。 
代碼如下:

@EnableTransactionManagement
@SpringBootApplication
public class ProfiledemoApplication {

    // 其中 dataSource 框架會自動為我們注入
    @Bean
    public PlatformTransactionManager txManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean
    public Object testBean(PlatformTransactionManager platformTransactionManager) {
        System.out.println(">>>>>>>>>>" + platformTransactionManager.getClass().getName());
        return new Object();
    }

    public static void main(String[] args) {
        SpringApplication.run(ProfiledemoApplication.class, args);
    }
}

在Spring容器中,我們手工注解@Bean 將被優先加載,框架不會重新實例化其他的 PlatformTransactionManager 實現類。

然后在Service中,被 @Transactional 注解的方法,將支持事務。如果注解在類上,則整個類的所有方法都默認支持事務。

對於同一個工程中存在多個事務管理器要怎么處理,請看下面的實例,具體說明請看代碼中的注釋。

@EnableTransactionManagement // 開啟注解事務管理,等同於xml配置文件中的 <tx:annotation-driven />
@SpringBootApplication
public class ProfiledemoApplication implements TransactionManagementConfigurer {

    @Resource(name="txManager2")
    private PlatformTransactionManager txManager2;

    // 創建事務管理器1
    @Bean(name = "txManager1")
    public PlatformTransactionManager txManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    // 創建事務管理器2
    @Bean(name = "txManager2")
    public PlatformTransactionManager txManager2(EntityManagerFactory factory) {
        return new JpaTransactionManager(factory);
    }

    // 實現接口 TransactionManagementConfigurer 方法,其返回值代表在擁有多個事務管理器的情況下默認使用的事務管理器
    @Override
    public PlatformTransactionManager annotationDrivenTransactionManager() {
        return txManager2;
    }

    public static void main(String[] args) {
        SpringApplication.run(ProfiledemoApplication.class, args);
    }

}
@Component
public class DevSendMessage implements SendMessage {

    // 使用value具體指定使用哪個事務管理器
    @Transactional(value="txManager1")
    @Override
    public void send() {
        System.out.println(">>>>>>>>Dev Send()<<<<<<<<");
        send2();
    }

    // 在存在多個事務管理器的情況下,如果使用value具體指定
    // 則默認使用方法 annotationDrivenTransactionManager() 返回的事務管理器
    @Transactional
    public void send2() {
        System.out.println(">>>>>>>>Dev Send2()<<<<<<<<");
    }

}

注: 
如果Spring容器中存在多個 PlatformTransactionManager 實例,並且沒有實現接口 TransactionManagementConfigurer 指定默認值,在我們在方法上使用注解 @Transactional 的時候,就必須要用value指定,如果不指定,則會拋出異常。

對於系統需要提供默認事務管理的情況下,實現接口 TransactionManagementConfigurer 指定。

對有的系統,為了避免不必要的問題,在業務中必須要明確指定 @Transactional 的 value 值的情況下。不建議實現接口 TransactionManagementConfigurer,這樣控制台會明確拋出異常,開發人員就不會忘記主動指定。

http://blog.csdn.net/catoop/article/details/50595702

注意的幾點:

1  @Transactional 只能被應用到public方法上, 對於其它非public的方法,如果標記了@Transactional也不會報錯,但方法沒有事務功能.

 

2 默認情況下,一個有事務方法, 遇到RuntiomeException 時會回滾 .  遇到 受檢查的異常 是不會回滾 的. 要想所有異常都回滾,要加上 @Transactional( rollbackFor={Exception.class,其它異常}) . 

 

@Transactional  的所有可選屬性如下: 

 

屬性 類型 默認值 說明
propagation Propagation枚舉 REQUIRED 事務傳播屬性 (下有說明)
isolation isolation枚舉 DEFAULT 事務隔離級別 (另有說明)
readOnly boolean false 是否只讀
timeout int -1 超時(秒)
rollbackFor Class[] {} 需要回滾的異常類
rollbackForClassName String[] {} 需要回滾的異常類名
noRollbackFor Class[] {} 不需要回滾的異常類
noRollbackForClassName String[] {} 不需要回滾的異常類名


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM