成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

面試突擊:為什么事務(wù)@Transactional會(huì)失效?

開發(fā) 前端
本篇我們就來(lái)討論一下,導(dǎo)致事務(wù)失效的背后原因到底是啥?

導(dǎo)致 @Transactional 失效的常見場(chǎng)景有以下 5 個(gè):

  1. 非 public 修飾的方法。
  2. timeout 超時(shí)時(shí)間設(shè)置過小。
  3. 代碼中使用 try/catch 處理異常。
  4. 調(diào)用類內(nèi)部的 @Transactional 方法。
  5. 數(shù)據(jù)庫(kù)不支持事務(wù)。

很多人只知道答案但不知道原因,這就像只談戀愛不結(jié)婚一樣,是不能讓人接受的,所以本篇我們就來(lái)討論一下,導(dǎo)致事務(wù)失效的背后原因到底是啥?

在以上 5 種場(chǎng)景中,第 2 種(timeout 超時(shí)時(shí)間設(shè)置過小)和第 5 種(數(shù)據(jù)庫(kù)不支持事務(wù))很好理解,我們這里就不贅述了,本文我們重點(diǎn)來(lái)討論其他 3 種情況。

1、非 public 修飾的方法

非 public 修飾的方法上,即使加了 @Transactional 事務(wù)依然不會(huì)生效,原因是因?yàn)?@Transactional 使用的是 Spring AOP 實(shí)現(xiàn)的,而 Spring AOP 是通過動(dòng)態(tài)代理實(shí)現(xiàn)的,而 @Transactional 在生成代理時(shí)會(huì)判斷,如果方法為非 public 修飾的方法,則不生成代理對(duì)象,這樣也就沒辦法自動(dòng)執(zhí)行事務(wù)了,它的部分實(shí)現(xiàn)源碼如下:

protected TransactionAttribute computeTransactionAttribute(Method method, Class<?> targetClass) {
// Don't allow no-public methods as required.
// 非 public 方法,設(shè)置為 null
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
}
// 后面代碼省略....
}

2、try/catch 導(dǎo)致事務(wù)失效

@Transactional 執(zhí)行流程是:@Transactional 會(huì)在方法執(zhí)行前,會(huì)自動(dòng)開啟事務(wù);在方法成功執(zhí)行完,會(huì)自動(dòng)提交事務(wù);如果方法在執(zhí)行期間,出現(xiàn)了異常,那么它會(huì)自動(dòng)回滾事務(wù)。

然而如果在方法中自行添加了 try/catch 之后,事務(wù)就不會(huì)自動(dòng)回滾了,這是怎么回事呢?

造成這個(gè)問題的主要原因和 @Transactional 注解的實(shí)現(xiàn)有關(guān),它的部分實(shí)現(xiàn)源碼如下:

protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
throws Throwable {
// If the transaction attribute is null, the method is non-transactional.
final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
final String joinpointIdentification = methodIdentification(method, targetClass);

if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
// 自動(dòng)開啟事務(wù)
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
// 反射調(diào)用業(yè)務(wù)方法
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
// 異常時(shí),在 catch 邏輯中,自動(dòng)回滾事務(wù)
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
// 自動(dòng)提交事務(wù)
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
// .....
}
}

從上述實(shí)現(xiàn)源碼我們可以看出:當(dāng)執(zhí)行的方法中出現(xiàn)了異常,@Transactional 才能感知到,然后再執(zhí)行事務(wù)回滾,而當(dāng)開發(fā)者自行添加了 try/catch 之后,@Transactional 就感知不到異常了,從而就不會(huì)觸發(fā)事務(wù)的自動(dòng)回滾了,這就是為什么當(dāng) @Transactional 遇到 try/catch 之后就不會(huì)自動(dòng)回滾(事務(wù))的原因。

3、調(diào)用類內(nèi)用的 @Transactional 方法

當(dāng)調(diào)用類內(nèi)部的 @Transactional 修飾的方法時(shí),事務(wù)也不會(huì)生效,如下代碼所示:

@RequestMapping("/save")
public int saveMappping(UserInfo userInfo) {
return save(userInfo);
}
@Transactional
public int save(UserInfo userInfo) {
// 非空效驗(yàn)
if (userInfo == null ||
!StringUtils.hasLength(userInfo.getUsername()) ||
!StringUtils.hasLength(userInfo.getPassword()))
return 0;
int result = userService.save(userInfo);
int num = 10 / 0; // 此處設(shè)置一個(gè)異常
return result;
}

上述代碼在添加用戶之后即使遇到了異常,程序也沒有執(zhí)行回滾,這是因?yàn)?@Transactional 是基于 Spring AOP 實(shí)現(xiàn)的,而 Spring AOP 又是基于動(dòng)態(tài)代理實(shí)現(xiàn)的,而當(dāng)調(diào)用類內(nèi)部的方法時(shí),不是通過代理對(duì)象完成的,而是通過 this 對(duì)象實(shí)現(xiàn)的,這樣就繞過了代理對(duì)象,從而事務(wù)就失效了。

總結(jié)

非 public 修飾的方法在 @Transactional 實(shí)現(xiàn)時(shí)做了判斷,如果是非 public 則不會(huì)生成代理對(duì)象,所以事務(wù)就失效了;而調(diào)用類內(nèi)部的 @Transactional 修飾的方法時(shí),也是因?yàn)闆]有成功調(diào)用代理對(duì)象,是通過 this 來(lái)調(diào)用方法的,所以事務(wù)也失效了;@Transactional 在遇到開發(fā)者自定義的 try/catch 也會(huì)失效,這是因?yàn)?@Transactional 只有感知到了異常才會(huì)自動(dòng)回滾(事務(wù)),但如果用戶自定義了 try/catch,那么 @Transactional 就感知不到異常,所以也就不會(huì)自動(dòng)回滾事務(wù)了。

責(zé)任編輯:姜華 來(lái)源: 今日頭條
相關(guān)推薦

2022-09-14 19:50:22

事務(wù)場(chǎng)景流程

2022-04-13 20:53:15

Spring事務(wù)管理

2022-06-27 07:23:44

MySQL常量優(yōu)化

2022-01-18 06:59:50

HashMap循環(huán)底層

2015-07-10 09:28:09

事務(wù)性能

2022-07-27 07:36:01

TCP可靠性

2023-09-27 16:22:51

SpringMySQL原子性

2022-07-13 07:06:47

HTTPSHTTP協(xié)議

2022-01-24 07:01:20

安全多線程版本

2025-04-11 01:00:00

線程鎖Spring事務(wù)

2022-07-25 07:07:35

TCP客戶端服務(wù)器

2023-05-05 07:39:04

Spring事務(wù)面試

2023-09-28 09:07:54

注解失效場(chǎng)景

2022-03-02 07:36:37

池化技術(shù)Java線程池

2022-09-19 06:16:23

事務(wù)隔離級(jí)別Spring

2022-09-25 22:12:07

事務(wù)SpringBoot

2021-12-13 11:12:41

Spring事務(wù)失效

2022-09-12 22:27:05

編程式事務(wù)聲明式事務(wù)對(duì)象

2024-05-14 08:37:34

2022-01-27 07:02:52

JavaHashMap單線程
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 黄视频网址 | 久久99国产精一区二区三区 | 97在线观看| 国产精品夜间视频香蕉 | 亚洲第一成年免费网站 | 欧美一级毛片免费观看 | 国产精品自产拍 | 天堂久久天堂综合色 | 精品成人69xx.xyz | 日韩中文字幕在线观看 | 久久久久av| 久草热线 | 国产欧美在线 | 国产精品99久久久久久久久 | 欧美日韩中文在线 | 天堂色区 | 精品国产一区二区三区久久久四川 | 久久久精品综合 | 亚洲精品国产一区 | 久久久噜噜噜久久中文字幕色伊伊 | 国产免费拔擦拔擦8x高清 | 激情一区二区三区 | 国产婷婷精品 | 999视频 | 欧美精品一区二区在线观看 | 国产精品免费一区二区三区 | 成人小视频在线观看 | 亚洲欧美视频一区 | 黄色在线免费观看 | 99久久精品国产毛片 | 蜜桃视频一区二区三区 | 久久久久久高潮国产精品视 | 97人澡人人添人人爽欧美 | 伊人国产精品 | 久久精品视频网站 | 国产91精品网站 | 精品国产乱码久久久久久a丨 | 免费在线a视频 | 日韩欧美在线观看 | 91在线观看 | 欧洲一区在线观看 |