欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

踩坑之spring事務(wù),非事務(wù)方法與事務(wù)方法執(zhí)行相互調(diào)用方式

 更新時(shí)間:2023年07月26日 09:08:44   作者:西風(fēng)一任秋  
這篇文章主要介紹了踩坑之spring事務(wù),非事務(wù)方法與事務(wù)方法執(zhí)行相互調(diào)用方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

踩坑spring事務(wù),非事務(wù)方法與事務(wù)方法執(zhí)行相互調(diào)用

項(xiàng)目環(huán)境 sprinigboot

下面開始問題描述,發(fā)生的過程有點(diǎn)長,想直接看方案的直接跳過哦~

最近在做項(xiàng)目中有個(gè)業(yè)務(wù)是每天定時(shí)更新xx的數(shù)據(jù),某條記錄更新中數(shù)據(jù)出錯(cuò),不影響整體數(shù)據(jù),只需記錄下來并回滾當(dāng)條記錄所關(guān)聯(lián)的表數(shù)據(jù);

好啊,這個(gè)簡單,接到任務(wù)后,樓主我三下五除二就寫完了,由于這個(gè)業(yè)務(wù)還是有些麻煩,我就在一個(gè)service里拆成了兩個(gè)方法去執(zhí)行,一個(gè)方法(A)是查詢數(shù)據(jù)與驗(yàn)證組裝數(shù)據(jù),另外一個(gè)方法(B)更新這條數(shù)據(jù)所對應(yīng)的表(執(zhí)行的時(shí)候是方法A中調(diào)用方法B);

由于這個(gè)數(shù)據(jù)是循環(huán)更新,所以我想的是,一條數(shù)據(jù)更新失敗直接回滾此條數(shù)據(jù)就是,不會(huì)影響其他數(shù)據(jù),其他的照常更新,所以我就在方法B上加了事務(wù),方法A沒有加;

以為很完美,自測一下正常,ok通過,再測試一下報(bào)錯(cuò)情況,是否回滾,一測,沒回滾,懵圈兒?

以為代碼寫錯(cuò)了,改了幾處地方,再測了幾次,均沒回滾.這下是真難受了.

好啦,寫到這里,相信各位看官心里肯定在嘲諷老弟了,spring的傳播機(jī)制都沒搞明白(/難受)

下面開始一步步分析解決問題

首先我們來看下spring事務(wù)的傳播機(jī)制及原因分析

  • PROPAGATION_REQUIRED -- 支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就新建一個(gè)事務(wù)。這是最常見的選擇。
  • PROPAGATION_SUPPORTS -- 支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就以非事務(wù)方式執(zhí)行。
  • PROPAGATION_MANDATORY -- 支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就拋出異常。
  • PROPAGATION_REQUIRES_NEW -- 新建事務(wù),如果當(dāng)前存在事務(wù),把當(dāng)前事務(wù)掛起。
  • PROPAGATION_NOT_SUPPORTED -- 以非事務(wù)方式執(zhí)行操作,如果當(dāng)前存在事務(wù),就把當(dāng)前事務(wù)掛起。
  • PROPAGATION_NEVER -- 以非事務(wù)方式執(zhí)行,如果當(dāng)前存在事務(wù),則拋出異常。
  • PROPAGATION_NESTED -- 如果當(dāng)前存在事務(wù),則在嵌套事務(wù)內(nèi)執(zhí)行。如果當(dāng)前沒有事務(wù),則進(jìn)行與PROPAGATION_REQUIRED類似的操作。 

spring默認(rèn)的是PROPAGATION_REQUIRED機(jī)制,如果方法A標(biāo)注了注解@Transactional 是完全沒問題的,執(zhí)行的時(shí)候傳播給方法B,因?yàn)榉椒ˋ開啟了事務(wù),線程內(nèi)的connection的屬性autoCommit=false,并且執(zhí)行到方法B時(shí),事務(wù)傳播依然是生效的,得到的還是方法A的connection,autoCommit還是為false,所以事務(wù)生效;反之,如果方法A沒有注解@Transactional 時(shí),是不受事務(wù)管理的,autoCommit=true,那么傳播給方法B的也為true,執(zhí)行完自動(dòng)提交,即使B標(biāo)注了@Transactional ;

在一個(gè)Service內(nèi)部,事務(wù)方法之間的嵌套調(diào)用,普通方法和事務(wù)方法之間的嵌套調(diào)用,都不會(huì)開啟新的事務(wù).

是因?yàn)閟pring采用動(dòng)態(tài)代理機(jī)制來實(shí)現(xiàn)事務(wù)控制,而動(dòng)態(tài)代理最終都是要調(diào)用原始對象的,而原始對象在去調(diào)用方法時(shí),是不會(huì)再觸發(fā)代理了!

所以以上就是為什么我在沒有標(biāo)注事務(wù)注解方法A里去調(diào)用標(biāo)注有事務(wù)注解方法B而沒有事務(wù)滾回的原因;

看到這里,有的看官可能在想,你在方法A上標(biāo)個(gè)注解不就完了嗎?為什么非要標(biāo)注在方法B上?

由于我這里是循環(huán)更新數(shù)據(jù),調(diào)用一次方法B就更新一次數(shù)據(jù),涉及到幾張表,需要執(zhí)行幾條update sql, 一條數(shù)據(jù)更新失敗不影響所有數(shù)據(jù),所以說一條數(shù)據(jù)更新執(zhí)行完畢后就提交一次事務(wù),如果標(biāo)注在方法A上,要所有的都執(zhí)行完畢了才提交事務(wù),這樣子是有問題滴.

下邊先上下代碼

方法A:無事務(wù)控制

方法B:有事務(wù)控制

方法B處理失敗手動(dòng)拋出異常觸發(fā)回滾:

方法A調(diào)用方法B:

從上圖可以看到,如果方法B中User更新出錯(cuò)后需要回滾RedPacket數(shù)據(jù),所以User更新失敗就拋出了繼承自RuntimeException的自定義異常,并且在調(diào)用方把這個(gè)異常catch到重新拋出,觸發(fā)事務(wù)回滾,但是并沒有執(zhí)行;

下面是解決方案

1.把方法B抽離到另外一個(gè)XXService中去,并且在這個(gè)Service中注入XXService,使用XXService調(diào)用方法B;

顯然,這種方式一點(diǎn)也不優(yōu)雅,且要產(chǎn)生很多冗余文件,看起來很煩,實(shí)際開發(fā)中也幾乎沒人這么做吧?.

反正我不建議采用此方案;

2.通過在方法內(nèi)部獲得當(dāng)前類代理對象的方式,通過代理對象調(diào)用方法B

上面說了:動(dòng)態(tài)代理最終都是要調(diào)用原始對象的,而原始對象在去調(diào)用方法時(shí),是不會(huì)再觸發(fā)代理了!

所以我們就使用代理對象來調(diào)用,就會(huì)觸發(fā)事務(wù);

綜上解決方案,我覺得第二種方式簡直方便到炸. 那怎么獲取代理對象呢?

這里提供兩種方式:

  • 1.使用 ApplicationContext 上下文對象獲取該對象;
  • 2.使用 AopContext.currentProxy() 獲取代理對象,但是需要配置exposeProxy=true

我這里使用的是第二種解決方案,具體操作如下:

springboot啟動(dòng)類加上注解:

@EnableAspectJAutoProxy(exposeProxy = true)

方法內(nèi)部獲取代理對象調(diào)用方法

完了后再測試,數(shù)據(jù)順利回滾,至此,問題得到解決!

都是事務(wù)這塊兒基礎(chǔ)太差的錯(cuò)啊~~

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • jconsole使用介紹(圖文)

    jconsole使用介紹(圖文)

    大家在學(xué)習(xí)java的時(shí)候,難免會(huì)對jvm進(jìn)行一些深入的了解。推薦大家使用jdk下面的jconsole.exe來輔助理解jvm的一些概念
    2015-12-12
  • Spring的DI依賴注入詳解

    Spring的DI依賴注入詳解

    這篇文章主要為大家介紹了Spring的DI依賴注入,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-01-01
  • JPA原生SQL(自定義SQL)分頁查詢邏輯詳解

    JPA原生SQL(自定義SQL)分頁查詢邏輯詳解

    這篇文章主要介紹了JPA原生SQL(自定義SQL)分頁查詢邏輯詳解,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • java中Properties文件加載和使用方法

    java中Properties文件加載和使用方法

    這篇文章主要為大家詳細(xì)介紹了java中Properties文件加載和使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-03-03
  • Java生成UUID的常用方式示例代碼

    Java生成UUID的常用方式示例代碼

    UUID保證對在同一時(shí)空中的所有機(jī)器都是唯一的,通常平臺會(huì)提供生成的API,按照開放軟件基金會(huì)(OSF)制定的標(biāo)準(zhǔn)計(jì)算,用到了以太網(wǎng)卡地址、納秒級時(shí)間、芯片ID碼和許多可能的數(shù)字,下面這篇文章主要給大家介紹了關(guān)于Java生成UUID的常用方式,需要的朋友可以參考下
    2023-05-05
  • 使用IDEA創(chuàng)建SpringBoot項(xiàng)目

    使用IDEA創(chuàng)建SpringBoot項(xiàng)目

    本文詳細(xì)介紹了使用SpringBoot創(chuàng)建項(xiàng)目,包含配置、啟動(dòng)、開發(fā)環(huán)境配置等,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-12-12
  • SpringBoot服務(wù)器端解決跨域問題

    SpringBoot服務(wù)器端解決跨域問題

    這篇文章主要介紹了SpringBoot服務(wù)器端解決跨域問題,幫助大家更好的理解和使用springboot框架,感興趣的朋友可以了解下
    2020-11-11
  • springboot項(xiàng)目編寫發(fā)送異常日志到企微工具包的操作方法

    springboot項(xiàng)目編寫發(fā)送異常日志到企微工具包的操作方法

    本文介紹了Springboot項(xiàng)目如何編寫發(fā)送異常日志到企業(yè)微信的工具包,內(nèi)容包括創(chuàng)建基礎(chǔ)Bean、配置類、pom依賴等步驟,并展示了如何通過nacos進(jìn)行配置,這為開發(fā)者提供了一種有效的日志管理方案,方便快速定位和處理項(xiàng)目中的異常問題,感興趣的朋友跟隨小編一起看看吧
    2024-09-09
  • 使用Sentinel自定義返回和實(shí)現(xiàn)區(qū)分來源方式

    使用Sentinel自定義返回和實(shí)現(xiàn)區(qū)分來源方式

    這篇文章主要介紹了使用Sentinel自定義返回和實(shí)現(xiàn)區(qū)分來源方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • SpringBoot集成jjwt和使用方式

    SpringBoot集成jjwt和使用方式

    本文詳細(xì)介紹了JWT依賴(以jjwt為例)的引入和使用方法,首先,需要在項(xiàng)目中引入jwt依賴,隨后在Spring的啟動(dòng)類application.yml中進(jìn)行相應(yīng)配置,最后,提供了一份完整的jwt工具類代碼,供讀者直接使用,以上內(nèi)容便是作者的個(gè)人經(jīng)驗(yàn)分享,期望能為讀者提供參考并得到支持
    2024-10-10

最新評論