电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術(shù)文章
文章詳情頁

關(guān)于Spring的@Transaction導(dǎo)致數(shù)據(jù)庫回滾全部生效問題(又刪庫跑路)

瀏覽:21日期:2023-07-14 18:27:58
1 前言

很多需要使用事務(wù)的場景,都只是在方法上直接添加個(gè)@Transactional注解

關(guān)于Spring的@Transaction導(dǎo)致數(shù)據(jù)庫回滾全部生效問題(又刪庫跑路)

但是,你以為這真的夠了嗎?

事務(wù)如果未達(dá)到完美效果,在開發(fā)和測試階段都難以被發(fā)現(xiàn),因?yàn)槟汶y以考慮到太多意外場景。但當(dāng)業(yè)務(wù)數(shù)據(jù)量發(fā)展,就可能導(dǎo)致大量數(shù)據(jù)不一致的問題,就會造成前人栽樹后人踩坑,需要大量人力排查解決問題和修復(fù)數(shù)據(jù)。

2 如何確認(rèn)Spring事務(wù)生效了?

使用@Transactional一鍵開啟聲明式事務(wù), 這就真的事務(wù)生效了?過于信任框架總有“意外驚喜”。來看如下案例

領(lǐng)域?qū)?實(shí)體

關(guān)于Spring的@Transaction導(dǎo)致數(shù)據(jù)庫回滾全部生效問題(又刪庫跑路)

關(guān)于Spring的@Transaction導(dǎo)致數(shù)據(jù)庫回滾全部生效問題(又刪庫跑路)

領(lǐng)域服務(wù)

createUserError1調(diào)用private方法

關(guān)于Spring的@Transaction導(dǎo)致數(shù)據(jù)庫回滾全部生效問題(又刪庫跑路)

createUserPrivate,被@Transactional注解。當(dāng)傳入的用戶名包含test則拋異常,讓用戶的創(chuàng)建操作失敗

關(guān)于Spring的@Transaction導(dǎo)致數(shù)據(jù)庫回滾全部生效問題(又刪庫跑路)

getUserCount

關(guān)于Spring的@Transaction導(dǎo)致數(shù)據(jù)庫回滾全部生效問題(又刪庫跑路)

用戶接口層

調(diào)用UserService#createUserError1

關(guān)于Spring的@Transaction導(dǎo)致數(shù)據(jù)庫回滾全部生效問題(又刪庫跑路)

測試結(jié)果即便用戶名不合法,用戶也能創(chuàng)建成功。刷新瀏覽器,多次發(fā)現(xiàn)有十幾個(gè)的非法用戶注冊。 @Transactional生效原則 public方法

除非特殊配置(比如使用AspectJ靜態(tài)織入實(shí)現(xiàn)AOP),@Transactional必須定義在public方法才生效。

因?yàn)镾pring的AOP,private方法無法被代理到,自然也無法動態(tài)增強(qiáng)事務(wù)處理邏輯。

那簡單,把createUserPrivate方法改為public不就行了。但發(fā)現(xiàn)事務(wù)依舊未生效

必須通過代理過的類從外部調(diào)用目標(biāo)方法

要調(diào)用增強(qiáng)過的方法必然是調(diào)用代理后的對象。嘗試修改UserService,注入一個(gè)self,然后再通過self實(shí)例調(diào)用標(biāo)記有 @Transactional 注解的createUserPublic方法。設(shè)置斷點(diǎn)可以看到,self是由Spring通過CGLIB方式增強(qiáng)過的類:

關(guān)于Spring的@Transaction導(dǎo)致數(shù)據(jù)庫回滾全部生效問題(又刪庫跑路)

CGLIB通過繼承實(shí)現(xiàn)代理類,private方法在子類不可見,所以無法進(jìn)行事務(wù)增強(qiáng)。而this指針代表調(diào)用對象本身,Spring不可能注入this,所以通過this訪問方法必然不是代理。把this改為self,這時(shí)即可驗(yàn)證事務(wù)生效:非法的用戶注冊操作可回滾。

雖然在UserDomainService內(nèi)部注入自己調(diào)用自己的createUserPublic可正確實(shí)現(xiàn)事務(wù),但這不符常規(guī)。更合理的實(shí)現(xiàn)方式是,讓Controller直接調(diào)用之前定義的UserService的createUserPublic方法。

關(guān)于Spring的@Transaction導(dǎo)致數(shù)據(jù)庫回滾全部生效問題(又刪庫跑路)

this/self/Controller調(diào)用UserDomainService

關(guān)于Spring的@Transaction導(dǎo)致數(shù)據(jù)庫回滾全部生效問題(又刪庫跑路)

this自調(diào)用

無法走到Spring代理類

后兩種

調(diào)用的Spring注入的UserService,通過代理調(diào)用才有機(jī)會對createUserPublic方法進(jìn)行動態(tài)增強(qiáng)。

推薦開發(fā)時(shí)打開Debug日志以了解Spring事務(wù)實(shí)現(xiàn)的細(xì)節(jié)。比如JPA數(shù)據(jù)庫訪問,開啟Debug日志:logging.level.org.springframework.orm.jpa=DEBUG

開啟日志后再比較下在UserService中this調(diào)用、Controller中通過注入的UserService Bean調(diào)用createUserPublic的區(qū)別。

很明顯,this調(diào)用因沒走代理,事務(wù)沒有在createUserPublic生效,只在Repository的save生效:

// 在UserService中通過this調(diào)用public的createUserPublic[23:04:30.748] [http-nio-45678-exec-5] [DEBUG] [o.s.orm.jpa.JpaTransactionManager:370 ] - Creating new transaction with name [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT[DEBUG] [o.s.orm.jpa.JpaTransactionManager :370 ] - Creating new transaction with name [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT//在Controller中通過注入的UserService Bean調(diào)用createUserPublic[10:10:47.750] [http-nio-45678-exec-6] [DEBUG] [o.s.orm.jpa.JpaTransactionManager :370 ] - Creating new transaction with name [org.geekbang.time.commonmistakes.transaction.demo1.UserService.createUserPublic]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT

這種實(shí)現(xiàn)在Controller里處理異常顯得繁瑣,還不如直接把createUserWrong2加@Transactional注解,然后在Controller中直接調(diào)用該方法。這既能從外部(Controller中)調(diào)用UserService方法,方法又是public的能夠被動態(tài)代理AOP增強(qiáng)。

小結(jié)

務(wù)必確認(rèn)調(diào)用被@Transactional注解標(biāo)記的方法被public修飾,并且是通過Spring注入的Bean進(jìn)行調(diào)用。

但有時(shí)因沒有正確處理異常,導(dǎo)致事務(wù)即便生效也不一定能回滾。

2 事務(wù)生效不代表能正確回滾

AOP實(shí)現(xiàn)事務(wù):使用try/catch包裹@Transactional注解的方法:

當(dāng)方法出現(xiàn)異常并滿足一定條件,在catch里可設(shè)置事務(wù)回滾 沒有異常則直接提交事務(wù) 一定條件

只有異常傳播出了被@Transactional注解的方法,事務(wù)才能回滾。

Spring的 TransactionAspectSupport#invokeWithinTransaction 就是在處理事務(wù)。觀察源碼得知,只有捕獲到異常后才能進(jìn)行后續(xù)事務(wù)處理:

關(guān)于Spring的@Transaction導(dǎo)致數(shù)據(jù)庫回滾全部生效問題(又刪庫跑路)

默認(rèn)情況下,出現(xiàn)RuntimeException(非受檢異常)或Error,Spring才會回滾事務(wù)。

Spring的DefaultTransactionAttribute:

受檢異常一般是業(yè)務(wù)異常或類似另一種方法的返回值,出現(xiàn)這種異常可能業(yè)務(wù)還能完成,所以不會主動回滾 而Error或RuntimeException代表非預(yù)期結(jié)果,應(yīng)該回滾

關(guān)于Spring的@Transaction導(dǎo)致數(shù)據(jù)庫回滾全部生效問題(又刪庫跑路)

事務(wù)無法正常回滾的各種慘案 異常無法傳播出方法

關(guān)于Spring的@Transaction導(dǎo)致數(shù)據(jù)庫回滾全部生效問題(又刪庫跑路)

受檢異常

注冊的同時(shí)會有一次文件讀,若讀文件失敗,希望用戶注冊的DB操作回滾。因讀文件拋的是受檢異常,createUserError2傳播出去的也是受檢異常

關(guān)于Spring的@Transaction導(dǎo)致數(shù)據(jù)庫回滾全部生效問題(又刪庫跑路)關(guān)于Spring的@Transaction導(dǎo)致數(shù)據(jù)庫回滾全部生效問題(又刪庫跑路)

以上方法雖然避開了事務(wù)不生效的坑,但因異常處理不當(dāng),導(dǎo)致異常時(shí)依舊不回滾事務(wù)。

修復(fù)回滾失敗bug 1 手動設(shè)置讓當(dāng)前事務(wù)處回滾態(tài)

若希望自己捕獲異常并處理,可手動設(shè)置讓當(dāng)前事務(wù)處回滾態(tài)

關(guān)于Spring的@Transaction導(dǎo)致數(shù)據(jù)庫回滾全部生效問題(又刪庫跑路)

查看日志,事務(wù)確定回滾。

Transactional code has requested rollback:手動請求回滾。關(guān)于Spring的@Transaction導(dǎo)致數(shù)據(jù)庫回滾全部生效問題(又刪庫跑路)關(guān)于Spring的@Transaction導(dǎo)致數(shù)據(jù)庫回滾全部生效問題(又刪庫跑路)

2 注解中聲明,期望所有Exception都回滾事務(wù) 突破默認(rèn)不回滾受檢異常的限制

關(guān)于Spring的@Transaction導(dǎo)致數(shù)據(jù)庫回滾全部生效問題(又刪庫跑路)

查看日志,提示回滾:

關(guān)于Spring的@Transaction導(dǎo)致數(shù)據(jù)庫回滾全部生效問題(又刪庫跑路)

該案例有DB操作、IO操作,在IO操作問題時(shí)期望DB事務(wù)也回滾,以確保邏輯一致性。 小結(jié)

由于異常處理不正確,導(dǎo)致雖然事務(wù)生效,但出現(xiàn)異常時(shí)沒回滾。Spring默認(rèn)只對被@Transactional注解的方法出現(xiàn)RuntimeException和Error時(shí)回滾,所以若方法捕獲了異常,就需要通過手寫代碼處理事務(wù)回滾。若希望Spring針對其他異常也可回滾,可相應(yīng)配置@Transactional注解的rollbackFor和noRollbackFor屬性覆蓋Spring的默認(rèn)配置。

有些業(yè)務(wù)可能包含多次DB操作,不一定希望將兩次操作作為一個(gè)事務(wù),這時(shí)就需仔細(xì)考慮事務(wù)傳播的配置。

3 事務(wù)傳播配置是否符合業(yè)務(wù)邏輯

案例

用戶注冊:會插入一個(gè)主用戶到用戶表,還會注冊一個(gè)關(guān)聯(lián)的子用戶。期望將子用戶注冊的DB操作作為一個(gè)獨(dú)立事務(wù),即使失敗也不影響注冊主用戶的流程。

UserService:創(chuàng)建主、子用戶

關(guān)于Spring的@Transaction導(dǎo)致數(shù)據(jù)庫回滾全部生效問題(又刪庫跑路)

SubUserService:使子用戶注冊失敗。期望子用戶注冊作為一個(gè)事務(wù)單獨(dú)回滾而不影響注冊主用戶

關(guān)于Spring的@Transaction導(dǎo)致數(shù)據(jù)庫回滾全部生效問題(又刪庫跑路)

啟動調(diào)用后查看日志:事務(wù)回滾了

關(guān)于Spring的@Transaction導(dǎo)致數(shù)據(jù)庫回滾全部生效問題(又刪庫跑路)

不對呀!因?yàn)檫\(yùn)行時(shí)異常逃出被@Transactional注解的createUserWrong,Spring當(dāng)然會回滾事務(wù)。若期望主方法不回滾,應(yīng)捕獲子方法所拋的異常。

修正方案

把subUserService#createSubUserWithExceptionError包上catch,這樣外層主方法createUserError2就不會出現(xiàn)異常

關(guān)于Spring的@Transaction導(dǎo)致數(shù)據(jù)庫回滾全部生效問題(又刪庫跑路)

啟動后查看日志注意到:

對createUserError2開啟異常處理 子方法因出現(xiàn)運(yùn)行時(shí)異常,標(biāo)記當(dāng)前事務(wù)為回滾 主方法捕獲異常并打印create sub user error 主方法提交事務(wù)

但Controller出現(xiàn)一個(gè)UnexpectedRollbackException,異常描述提示最終該事務(wù)回滾了且為靜默回滾:因createUserError2本身并無異常,只不過提交后發(fā)現(xiàn)子方法已把當(dāng)前事務(wù)設(shè)為回滾,無法完成提交。

明明無異常發(fā)生,但事務(wù)也不一定可提交因?yàn)橹鞣椒ㄗ灾饔脩舻倪壿嫼妥臃椒ㄗ宰佑脩舻倪壿嫗橥皇聞?wù),子邏輯標(biāo)記了事務(wù)需回滾,主邏輯自然也無法提交。那么修復(fù)方式就明確了,獨(dú)立子邏輯的事務(wù),即修正SubUserService注冊子用戶方法,為注解添加propagation = Propagation.REQUIRES_NEW設(shè)置REQUIRES_NEW事務(wù)傳播策略。即執(zhí)行到該方法時(shí)開啟新事務(wù),并掛起當(dāng)前事務(wù)。創(chuàng)建一個(gè)新事務(wù),若存在則暫停當(dāng)前事務(wù)。類似同名的EJB事務(wù)屬性。注:實(shí)際事務(wù)暫停不會對所有事務(wù)管理器外的開箱。 這特別適于org.springframework.transaction.jta.JtaTransactionManager ,這就需要javax.transaction.TransactionManager被提供給它(這是服務(wù)器特定的標(biāo)準(zhǔn)Java EE)

關(guān)于Spring的@Transaction導(dǎo)致數(shù)據(jù)庫回滾全部生效問題(又刪庫跑路)

主方法無變化,依舊需捕獲異常,防止異常外泄導(dǎo)致主事務(wù)回滾,重命名為createUserRight:

關(guān)于Spring的@Transaction導(dǎo)致數(shù)據(jù)庫回滾全部生效問題(又刪庫跑路)

修正后再查看日志

Creating new transaction with name createUserRight

對createUserRight開啟主方法事務(wù)createMainUser finish創(chuàng)建主用戶完成Suspending current transaction, creating new transaction with name createSubUserWithExceptionRight主事務(wù)掛起,開啟新事務(wù),即對createSubUserWithExceptionRight創(chuàng)建子用戶的邏輯Initiating transaction rollback子方法事務(wù)回滾Resuming suspended transaction after completion of inner transaction子方法事務(wù)完成,繼續(xù)主方法之前掛起的事務(wù)create sub user error:invalid status主方法捕獲到了子方法的異常Committing JPA transaction on EntityManager主方法的事務(wù)提交了,隨后我們在Controller里沒看到靜默回滾異常

小結(jié)

若方法涉及多次DB操作,并希望將它們作為獨(dú)立事務(wù)進(jìn)行提交或回滾,即需考慮細(xì)化配置事務(wù)傳播方式,即配置@Transactional注解的Propagation屬性。

4 總結(jié)

若要針對private方法啟用事務(wù),動態(tài)代理方式的AOP不可行,需要使用靜態(tài)織入方式的AOP,也就是在編譯期間織入事務(wù)增強(qiáng)代碼,可以配置Spring框架使用AspectJ來實(shí)現(xiàn)AOP。

以上就是關(guān)于Spring的@Transaction導(dǎo)致數(shù)據(jù)庫回滾全部生效問題(又刪庫跑路)的詳細(xì)內(nèi)容,更多關(guān)于Spring @Transaction數(shù)據(jù)庫回滾的資料請關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Spring
相關(guān)文章:
主站蜘蛛池模板: 澳门精准正版免费大全,2025新澳门全年免费,新澳天天开奖免费资料大全最新,新澳2025今晚开奖资料,新澳马今天最快最新图库 | 食药成分检测_调料配方还原_洗涤剂化学成分分析_饲料_百检信息科技有限公司 | 缝纫客| Pos机办理_个人商户免费POS机申请-拉卡拉办理网 | HYDAC过滤器,HYDAC滤芯,现货ATOS油泵,ATOS比例阀-东莞市广联自动化科技有限公司 | 水稻烘干机,小麦烘干机,大豆烘干机,玉米烘干机,粮食烘干机_巩义市锦华粮食烘干机械制造有限公司 水环真空泵厂家,2bv真空泵,2be真空泵-淄博真空设备厂 | 钢衬四氟管道_钢衬四氟直管_聚四氟乙烯衬里管件_聚四氟乙烯衬里管道-沧州汇霖管道科技有限公司 | 防火板_饰面耐火板价格、厂家_品牌认准格林雅 | 高压贴片电容|贴片安规电容|三端滤波器|风华电容代理南京南山 | 水厂自动化-水厂控制系统-泵站自动化|控制系统-闸门自动化控制-济南华通中控科技有限公司 | 贵阳用友软件,贵州财务软件,贵阳ERP软件_贵州优智信息技术有限公司 | 电脑刺绣_绣花厂家_绣花章仔_织唛厂家-[源欣刺绣]潮牌刺绣打版定制绣花加工厂家 | 高低温试验房-深圳高低温湿热箱-小型高低温冲击试验箱-爱佩试验设备 | 电磁流量计厂家_涡街流量计厂家_热式气体流量计-青天伟业仪器仪表有限公司 | 上海三信|ph计|酸度计|电导率仪-艾科仪器 | 亳州网络公司 - 亳州网站制作 - 亳州网站建设 - 亳州易天科技 | 黑龙江京科脑康医院-哈尔滨精神病医院哪家好_哈尔滨精神科医院排名_黑龙江精神心理病专科医院 | 定坤静电科技静电消除器厂家-除静电设备 | 变色龙云 - 打包app_原生app_在线制作平台_短链接_ip查询 | 干洗加盟网-洗衣店品牌排行-干洗设备价格-干洗连锁加盟指南 | 深圳市宏康仪器科技有限公司-模拟高空低压试验箱-高温防爆试验箱-温控短路试验箱【官网】 | 合肥钣金加工-安徽激光切割加工-机箱机柜加工厂家-合肥通快 | 粉丝机械,粉丝烘干机,粉丝生产线-招远市远东粉丝机械有限公司 | Copeland/谷轮压缩机,谷轮半封闭压缩机,谷轮涡旋压缩机,型号规格,技术参数,尺寸图片,价格经销商 CTP磁天平|小电容测量仪|阴阳极极化_双液系沸点测定仪|dsj电渗实验装置-南京桑力电子设备厂 | 泥沙分离_泥沙分离设备_泥砂分离机_洛阳隆中重工机械有限公司 | 济南玻璃安装_济南玻璃门_济南感应门_济南玻璃隔断_济南玻璃门维修_济南镜片安装_济南肯德基门_济南高隔间-济南凯轩鹏宇玻璃有限公司 | 密集架|电动密集架|移动密集架|黑龙江档案密集架-大量现货厂家销售 | 小型玉石雕刻机_家用玉雕机_小型万能雕刻机_凡刻雕刻机官网 | 专注氟塑料泵_衬氟泵_磁力泵_卧龙泵阀_化工泵专业品牌 - 梭川泵阀 | 出国劳务公司_正规派遣公司[严海] | China plate rolling machine manufacturer,cone rolling machine-Saint Fighter | 翅片管散热器价格_钢制暖气片报价_钢制板式散热器厂家「河北冀春暖气片有限公司」 | 交流伺服电机|直流伺服|伺服驱动器|伺服电机-深圳市华科星电气有限公司 | 石膏基自流平砂浆厂家-高强石膏基保温隔声自流平-轻质抹灰石膏粉砂浆批发-永康市汇利建设有限公司 | 飞利浦LED体育场灯具-吸顶式油站灯-飞利浦LED罩棚灯-佛山嘉耀照明有限公司 | 洛阳装修公司-洛阳整装一站式品牌-福尚云宅装饰 | 上海软件开发-上海软件公司-软件外包-企业软件定制开发公司-咏熠科技 | 多米诺-多米诺世界纪录团队-多米诺世界-多米诺团队培训-多米诺公关活动-多米诺创意广告-多米诺大型表演-多米诺专业赛事 | 考试试题_试卷及答案_诗词单词成语 - 优易学| 浙江美尔凯特智能厨卫股份有限公司| 储能预警-储能消防系统-电池舱自动灭火装置-四川千页科技股份有限公司官网 |