天天看點

Spring Boot 事務的使用

版權聲明:本文為部落客原創文章,未經部落客允許不得轉載。 https://blog.csdn.net/catoop/article/details/50595702

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,這樣控制台會明确抛出異常,開發人員就不會忘記主動指定。