解析spring事務(wù)管理@Transactional為什么要添加rollbackFor=Exception.class
spring中事務(wù)處理原理
利用aop生成代理對(duì)象執(zhí)行帶有Transactional事務(wù)注解的方法業(yè)務(wù)邏輯.項(xiàng)目啟動(dòng)過(guò)程中會(huì)生成代理對(duì)象并將Transactional注解中的屬性進(jìn)行解析加載處理.在方法執(zhí)行過(guò)程中如果出現(xiàn)異常,會(huì)根據(jù)注解配置決定是進(jìn)入到事務(wù)回滾處理還是事務(wù)提交處理邏輯中,事務(wù)回滾處理邏輯中最終還是基于數(shù)據(jù)庫(kù)的事務(wù)回滾處理.
異常的分類(lèi)

案例說(shuō)明
以自定義異常為例說(shuō)明一下@Transactional中是否指定rollbackFor=Exception.class的區(qū)別
未指定rollbackFor屬性
@Transactional
@GetMapping("/addSysMenu")
public void addSysMenu() throws Exception {
// 更新菜單名稱(chēng)(將id為1的菜單名修改為系統(tǒng)管理測(cè)試)
int k = sysMenuDao.updateSysMenu(1, "系統(tǒng)管理測(cè)試");
System.out.println(k);
// 自定義異常,拋出非運(yùn)行期異常
throw new Exception("自定義異常");
// 執(zhí)行結(jié)果:程序終止,數(shù)據(jù)庫(kù)中菜單id為1的菜單名修改成功.說(shuō)明事物沒(méi)有回滾.
}
指定rollbackFor屬性
@Transactional(rollbackFor = Exception.class)
@GetMapping("/addSysMenu")
public void addSysMenu(String menuName) throws Exception {
// 更新菜單名稱(chēng)(將id為1的菜單名修改為系統(tǒng)管理測(cè)試)
int k = sysMenuDao.updateSysMenu(1, "系統(tǒng)管理測(cè)試");
System.out.println(k);
// 自定義異常,拋出非運(yùn)行期異常
throw new Exception("自定義異常");
// 執(zhí)行結(jié)果:程序終止,數(shù)據(jù)庫(kù)中菜單id為1的菜單名沒(méi)有修改.說(shuō)明事物回滾.
}
原因分析
其他帖子都說(shuō)如果不加的話僅支持運(yùn)行期異常以及error錯(cuò)誤類(lèi)型.對(duì)于非運(yùn)行期異常是不支持的.這里提供一下這種說(shuō)法的來(lái)源.
先看一下@Transactional注解中關(guān)于rollbackFor的使用說(shuō)明
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
// 省略部分代碼............
// By default, a transaction will be rolling back on {@link RuntimeException} and {@link Error} but not on checked exceptions (business exceptions).
// 翻譯:指定事物回滾的異常類(lèi)型,默認(rèn)僅對(duì)于運(yùn)行期異常和錯(cuò)誤支持事務(wù)回滾,對(duì)于檢查異常(業(yè)務(wù)異常是不支持的)
Class<? extends Throwable>[] rollbackFor() default {};
}
至于加上@Transactional中指定rollbackFor=Exception.class以后是如何起作用的接著往下看.
spring中事務(wù)回滾的大概邏輯是,發(fā)生異常之后,會(huì)根據(jù)配置的事務(wù)屬性判斷是否進(jìn)行回滾的處理,如果不進(jìn)行事務(wù)回滾則直接進(jìn)行事務(wù)提交.這里重要的體現(xiàn)是在:TransactionAspectSupport.java中completeTransactionAfterThrowing
// 發(fā)生異常時(shí)事務(wù)處理方式
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
// 省略部分代碼.......
// 判斷異常是否為運(yùn)行期異?;蚴莈rror,如果是則執(zhí)行回滾處理,如果不是則提交事務(wù)
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
// 回滾事務(wù)處理
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
// 省略部分代碼......
}
else {
// 提交事務(wù)
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
// 省略部分代碼.......
}
}
}
而判斷事務(wù)是否支持回滾的處理在RuleBasedTransactionAttribute.java中transactionAttribute.rollbackOn()
// 判斷異常是否支持事務(wù)回滾處理
public boolean rollbackOn(Throwable ex) {
RollbackRuleAttribute winner = null;
// 省略部分代碼....................
// winner 是判斷@Transactional中是否有rollBackFor屬性,如果沒(méi)有則說(shuō)明沒(méi)有指定,按照默認(rèn)的方式進(jìn)行判斷(DefaultTransactionAttribute.java中rollbackOn),如果有則只判斷是否屬于NoRollbackRuleAttribute類(lèi)型,如果不是則說(shuō)明支持事務(wù)回滾.關(guān)于變量win對(duì)應(yīng)的RollbackRuleAttribute如何進(jìn)行的賦值下面繼續(xù).
if (winner == null) {
return super.rollbackOn(ex);
}
return !(winner instanceof NoRollbackRuleAttribute);
}
DefaultTransactionAttribute.java中rollbackOn,是否支持事務(wù)回滾的默認(rèn)判斷方式:是否是運(yùn)行期異?;蚴鞘欠袷清e(cuò)誤類(lèi)型(與Transactional注解中的rollbackFor屬性說(shuō)明相對(duì)應(yīng)).
public boolean rollbackOn(Throwable ex) {
return (ex instanceof RuntimeException || ex instanceof Error);
}
RollbackRuleAttribute中如何進(jìn)行的賦值問(wèn)題,具體來(lái)講是項(xiàng)目啟動(dòng)之后會(huì)掃描帶有Transactional注解的方法,然后將注解中標(biāo)注的屬性獲取之后進(jìn)行參數(shù)配置.具體體現(xiàn)是在:SpringTransactionAnnotationParser.java中parseTransactionAnnotation
protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
// 省略部分代碼.........
// 獲取注解上的rollbackFor屬性值
List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
rollbackRules.add(new RollbackRuleAttribute(rbRule));
}
// 省略部分代碼.........
return rbta;
}
至此關(guān)于為什么@Transactional為什么要添加rollbackFor=Exception.class原因以講述完畢!
到此這篇關(guān)于spring事務(wù)管理@Transactional為什么要添加rollbackFor=Exception.class的文章就介紹到這了,更多相關(guān)spring事務(wù)管理@Transactional內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Spring聲明式事務(wù)注解之@EnableTransactionManagement解析
- spring學(xué)習(xí)JdbcTemplate數(shù)據(jù)庫(kù)事務(wù)管理
- Spring框架JdbcTemplate數(shù)據(jù)庫(kù)事務(wù)管理完全注解方式
- SpringBoot2整合JTA組件實(shí)現(xiàn)多數(shù)據(jù)源事務(wù)管理
- 五分鐘教你手寫(xiě) SpringBoot 本地事務(wù)管理實(shí)現(xiàn)
- Spring事務(wù)管理原理及方法詳解
- 啟用Spring事務(wù)管理@EnableTransactionManagement示例解析
相關(guān)文章
Java常用類(lèi)之日期相關(guān)類(lèi)使用詳解
這篇文章主要為大家介紹了Java中常用類(lèi)的日期相關(guān)類(lèi)的用法教程,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Java有一定的幫助,需要的可以參考一下2022-08-08
Spring中BeanUtils.copyProperties的坑及解決
這篇文章主要介紹了Spring中BeanUtils.copyProperties的坑及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09
Spring security權(quán)限配置與使用大全
Spring Security 本質(zhì)上是借助一系列的 Servlet Filter來(lái)提供各種安全性功能,但這并不需要我們手動(dòng)去添加或者創(chuàng)建多個(gè)Filter,本文重點(diǎn)給大家介紹spring-security的配置與使用及實(shí)現(xiàn)方式,感興趣的朋友一起看看吧2021-09-09
JAVA大作業(yè)之圖書(shū)管理系統(tǒng)實(shí)現(xiàn)全解
隨著網(wǎng)絡(luò)技術(shù)的高速發(fā)展,計(jì)算機(jī)應(yīng)用的普及,利用計(jì)算機(jī)對(duì)圖書(shū)館的日常工作進(jìn)行管理勢(shì)在必行,本篇文章手把手帶你用Java實(shí)現(xiàn)一個(gè)圖書(shū)管理系統(tǒng),大家可以在過(guò)程中查缺補(bǔ)漏,提升水平2022-01-01
如何通過(guò)Kaptcha在Web頁(yè)面生成驗(yàn)證碼
這篇文章主要介紹了如何通過(guò)Kaptcha在Web頁(yè)面生成驗(yàn)證碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10
IDEA 使用 SpotBugs 找出你代碼中的bug問(wèn)題
這篇文章主要介紹了IDEA 使用 SpotBugs 找出你代碼中的bug問(wèn)題,重點(diǎn)給大家介紹SpotBugs 在 idea 中的安裝和使用,感興趣的朋友跟隨小編一起看看吧2021-07-07
Springboot錯(cuò)誤處理機(jī)制實(shí)現(xiàn)原理解析
這篇文章主要介紹了springboot錯(cuò)誤處理機(jī)制實(shí)現(xiàn)原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04

