Springboot中@Transactional注解與異常處理機(jī)制方式
Springboot @Transactional注解與異常處理機(jī)制
@Transactional注解的方法默認(rèn)會(huì)捕獲所有非檢查異常,即RuntimeException和Error,可以通過括號(hào)聲明顯示指定處理異常類,如Exception.class
關(guān)于異常處理機(jī)制:
當(dāng)代碼拋出異常時(shí),異常處理的優(yōu)先級(jí)如下:
- try-catch 塊:如果在代碼中使用了 try-catch 塊來(lái)捕獲異常,異常將會(huì)首先被 try-catch 塊捕獲并處理。只有在 try-catch 塊中未處理(重新拋出)異常時(shí),異常才會(huì)繼續(xù)傳播。
- @Transactional:如果異常從 try-catch 塊中傳播出來(lái),Spring 的事務(wù)管理器(由 @Transactional 注解管理)會(huì)捕獲異常并決定是否回滾事務(wù)。事務(wù)處理之后,異常繼續(xù)傳播。
- @ExceptionHandler:最后,異常會(huì)被全局異常處理器(由 @ControllerAdvice 和 @ExceptionHandler 注解管理)捕獲并處理。
因此,對(duì)于手動(dòng)捕獲的異常,需要手動(dòng)將其拋出才會(huì)被@Transactional處理器捕獲,全局處理器的優(yōu)先級(jí)最后,除了特殊的異常可能需要調(diào)整傳播順序,大部分不需要考慮其影響。
@Transactional錯(cuò)誤集錦以及如何正確使用
原理
@Transactional 是聲明式事務(wù)管理 編程中使用的注解,通過Spring AOP在注解修飾方法的前后織入事務(wù)管理的實(shí)現(xiàn)語(yǔ)句,所以開發(fā)者只需要通過一個(gè)注解就能代替一系列繁瑣的事務(wù)開始、事務(wù)關(guān)閉等重復(fù)性的編碼任務(wù)。
添加位置
- 接口實(shí)現(xiàn)類或接口實(shí)現(xiàn)方法上,而不是接口類中。
- 訪問權(quán)限:public 的方法才起作用。@Transactional 注解應(yīng)該只被應(yīng)用到 public 方法上,這是由 Spring AOP 的本質(zhì)決定的。
- 系統(tǒng)設(shè)計(jì):將標(biāo)簽放置在需要進(jìn)行事務(wù)管理的方法上,而不是放在所有接口實(shí)現(xiàn)類上:只讀的接口就不需要事務(wù)管理,由于配置了@Transactional就需要AOP攔截及事務(wù)的處理,可能影響系統(tǒng)性能。
錯(cuò)誤案例
1.同一個(gè)類中調(diào)用
public class A {
public void methodA() {
methodB();
// 其他操作
}
@Transactional
public void methodB() {
// 寫數(shù)據(jù)庫(kù)操作
}
}上面案例是錯(cuò)誤的基于Spring Aop的攔截機(jī)制,將會(huì)忽略事務(wù)。
解決方式如下:
@Service@AllArgsConstructorpublic class A { private B b; public void methodA() { b.methodB(); // 其他操作 }}@Servicepublic class B {
@Transactional public void methodB() { // 寫數(shù)據(jù)庫(kù)操作 } }
注意:這里的B類沒有用@Autowrire,構(gòu)造函數(shù)用Lombok的@AllArgsConstructor生成 自動(dòng)注入了。
2. @Transactional修飾方法不是public
public class TransactionalMistake {
@Transactional
private void method() {
// 寫數(shù)據(jù)庫(kù)操作
}
}這也是基于Spring AOP實(shí)現(xiàn)的注解所要滿足的要求。這個(gè)最簡(jiǎn)單, 直接把方法訪問類型改成public即可。
3. 不同的數(shù)據(jù)源
public class TransactionalMistake {
@Transactional
public void createOrder(Order order) {
orderRepo1.save(order);
orderRepo2.save(order);
}
}上面這個(gè)例子里的orderRepo1和orderRepo2是連接的兩個(gè)不同數(shù)據(jù)源。
默認(rèn)情況下,這種跨數(shù)據(jù)源的事務(wù)是不會(huì)成功的。
如果要在多個(gè)數(shù)據(jù)源之間實(shí)現(xiàn)事務(wù),那么可以引入JTA。
4. 回滾異常配置不正確
默認(rèn)情況下,僅對(duì)RuntimeException和Error進(jìn)行回滾。
如果不是的它們及它們的子孫異常的話,就不會(huì)回滾。
如果不是RuntimeException,但也希望觸發(fā)回滾,那么可以使用rollbackFor屬性來(lái)指定要回滾的異常。
public class TransactionalMistake {
@Transactional(rollbackFor = XXXException.class)
public void method() throws XXXException {
}
}5. 數(shù)據(jù)庫(kù)引擎不支持事務(wù)
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
這里的spring.jpa.database-platform配置主要用來(lái)設(shè)置hibernate使用的方言。
這里特地采用了MySQL5InnoDBDialect,主要為了保障在使用Spring Data JPA時(shí)候,Hibernate自動(dòng)創(chuàng)建表的時(shí)候使用InnoDB存儲(chǔ)引擎,不然就會(huì)以默認(rèn)存儲(chǔ)引擎MyISAM來(lái)建表,而MyISAM存儲(chǔ)引擎是沒有事務(wù)的。

總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- SpringBoot事務(wù)注解@Transactional失效場(chǎng)景與解決方案
- 如何使用Spring boot的@Transactional進(jìn)行事務(wù)管理
- Springboot @Transactional大事務(wù)處理的幾點(diǎn)建議
- SpringBoot?@Transactional事務(wù)不生效排查方式
- 解決SpringBoot中使用@Transactional注解遇到的問題
- springboot中使用@Transactional注解事物不生效的坑
- springboot中事務(wù)管理@Transactional的注意事項(xiàng)與使用場(chǎng)景
- Spring Boot的測(cè)試類中使用 @Transactional 注解
相關(guān)文章
Spring?WebFlux?與?WebClient?使用指南及最佳實(shí)踐
WebClient是Spring WebFlux模塊提供的非阻塞、響應(yīng)式HTTP客戶端,基于Project Reactor實(shí)現(xiàn),適用于高并發(fā)場(chǎng)景spring?webclient,本文給大家介紹Spring?WebFlux與WebClient使用指南及最佳實(shí)踐,感興趣的朋友一起看看吧2025-07-07
Java調(diào)用Coze?API詳細(xì)實(shí)現(xiàn)步驟
Coze是一款由字節(jié)跳動(dòng)推出的低代碼AI開發(fā)平臺(tái),讓非專業(yè)開發(fā)者也能輕松創(chuàng)建智能應(yīng)用,這篇文章主要介紹了Java調(diào)用Coze?API的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2026-01-01
Spring?Boot實(shí)現(xiàn)文件上傳下載
這篇文章主要為大家詳細(xì)介紹了Spring?Boot實(shí)現(xiàn)文件上傳下載,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08
mybatis實(shí)現(xiàn)查詢操作及獲得添加的ID
這篇文章主要介紹了mybatis實(shí)現(xiàn)查詢操作及獲得添加的ID,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-11-11

