1. 程式人生 > >SpringBoot jpa事務註解詳解

SpringBoot jpa事務註解詳解

@Transactional

spring 事務註解

1.簡單開啟事務管理

@EnableTransactionManagement // 啟註解事務管理,等同於xml配置方式的 <tx:annotation-driven />

2.事務註解詳解

預設遇到throw new RuntimeException(“…”);會回滾 
需要捕獲的throw new Exception(“…”);不會回滾

  • 指定回滾
@Transactional(rollbackFor=Exception.class) 
    public void methodName() {
       // 不會回滾
       throw new Exception("...");
    } 
  • 指定不回滾
@Transactional(noRollbackFor=Exception.class)
    public ItimDaoImpl getItemDaoImpl() {
        // 會回滾
        throw new RuntimeException("註釋");
    } 
  • 如果有事務,那麼加入事務,沒有的話新建一個(不寫的情況下)
    @Transactional(propagation=Propagation.REQUIRED) 
  • 容器不為這個方法開啟事務
@Transactional(propagation=Propagation.NOT_SUPPORTED)
  • 不管是否存在事務,都建立一個新的事務,原來的掛起,新的執行完畢,繼續執行老的事務
@Transactional(propagation=Propagation.REQUIRES_NEW) 
  • 必須在一個已有的事務中執行,否則丟擲異常
@Transactional(propagation=Propagation.MANDATORY)
  • 必須在一個沒有的事務中執行,否則丟擲異常(與Propagation.MANDATORY相反)
 @Transactional(propagation=Propagation.NEVER) 
  • 如果其他bean呼叫這個方法,在其他bean中宣告事務,那就用事務.如果其他bean沒有宣告事務,那就不用事務.
    @Transactional(propagation=Propagation.SUPPORTS) 

    /*
    public void methodName(){
       // 本類的修改方法 1
       update();
       // 呼叫其他類的修改方法
       otherBean.update();
       // 本類的修改方法 2
       update();
    }
    other失敗了不會影響 本類的修改提交成功
    本類update的失敗,other也失敗
    */

@Transactional(propagation=Propagation.NESTED)

  • readOnly=true只讀,不能更新,刪除
@Transactional (propagation = Propagation.REQUIRED,readOnly=true) 
  • 設定超時時間
@Transactional (propagation = Propagation.REQUIRED,timeout=30)
  • 設定資料庫隔離級別
@Transactional (propagation = Propagation.REQUIRED,isolation=Isolation.DEFAULT)

3.指定事務管理器

spring Boot 使用事務非常簡單,首先使用註解 @EnableTransactionManagement 開啟事務支援後,然後在訪問資料庫的Service方法上添加註解 @Transactional 便可。

關於事務管理器,不管是JPA還是JDBC等都實現自介面 PlatformTransactionManager 如果你新增的是 spring-boot-starter-jdbc 依賴,框架會預設注入 DataSourceTransactionManager 例項。如果你新增的是 spring-boot-starter-data-jpa 依賴,框架會預設注入 JpaTransactionManager 例項。

你可以在啟動類中新增如下方法,Debug測試,就能知道自動注入的是 PlatformTransactionManager 介面的哪個實現類。

3.1 列印專案事務管理器

@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為我們自動做了,這些對我們並不透明,如果你專案做的比較大,新增的持久化依賴比較多,我們還是會選擇人為的指定使用哪個事務管理器。 
程式碼如下:

3.2 指定事務管理器

@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 註解的方法,將支援事務。如果註解在類上,則整個類的所有方法都預設支援事務。

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

3.1 使用指定的事務管理器

@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()<<<<<<<<");
    }

}

注意:事務無效的情況

  • 需要在啟動類上面新增允許事務的註解@EnableTransactionManagement,類似<tx:annoation transactionmanger/>。
  • 在SpringBoot中使用jpa,表是通過對應的實體直接建立,預設情況下,表的引擎engine=MyISAM效能更好,但不提供事務支援,如果需要使用事務,需要將JPA建表的預設引擎修改為:InNoDB,直接修改配置檔案,如下:
# application.xml
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect

或者

# application.yml
spring:
    jpa:
        database-platform: org  .hibernate.dialect.MySQL5InnoDBDialect #InnoDB才能支援事務
  • 在service業務層丟擲異常但是被try,catch了,異常被吃掉,事務無法捕捉異常,就不回滾了。