<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          公司新來一個(gè)同事,把 @Transactional 事務(wù)注解運(yùn)用得爐火純青。。

          共 4137字,需瀏覽 9分鐘

           ·

          2022-07-12 23:01

          點(diǎn)擊關(guān)注公眾號,Java干貨及時(shí)送達(dá)

          推薦閱讀:Spring Cloud Alibaba 終于一統(tǒng)江湖!

          前兩天在工作中忙的焦頭爛額,涉及到@Transactional對于事務(wù)的控制,便仔細(xì)研究了一下,頗有所獲,花費(fèi)好了幾天測試整理,今天才發(fā)表出來,希望看到博客的老鐵們能有所獲吧。

          話不多說直奔正題。

          先簡單介紹一下Spring事務(wù)的傳播行為:

          所謂事務(wù)的傳播行為是指,如果在開始當(dāng)前事務(wù)之前,一個(gè)事務(wù)上下文已經(jīng)存在,此時(shí)有若干選項(xiàng)可以指定一個(gè)事務(wù)性方法的執(zhí)行行為。在TransactionDefinition定義中包括了如下幾個(gè)表示傳播行為的常量:

          • TransactionDefinition.PROPAGATION_REQUIRED:如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒有事務(wù),則創(chuàng)建一個(gè)新的事務(wù)。這是默認(rèn)值。
          • TransactionDefinition.PROPAGATION_REQUIRES_NEW:創(chuàng)建一個(gè)新的事務(wù),如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起。
          • TransactionDefinition.PROPAGATION_SUPPORTS:如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒有事務(wù),則以非事務(wù)的方式繼續(xù)運(yùn)行。
          • TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事務(wù)方式運(yùn)行,如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起。
          • TransactionDefinition.PROPAGATION_NEVER:以非事務(wù)方式運(yùn)行,如果當(dāng)前存在事務(wù),則拋出異常。
          • TransactionDefinition.PROPAGATION_MANDATORY:如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒有事務(wù),則拋出異常。
          • TransactionDefinition.PROPAGATION_NESTED:如果當(dāng)前存在事務(wù),則創(chuàng)建一個(gè)事務(wù)作為當(dāng)前事務(wù)的嵌套事務(wù)來運(yùn)行;如果當(dāng)前沒有事務(wù),則該取值等價(jià)于TransactionDefinition.PROPAGATION_REQUIRED
          • 另外,最新 Spring 面試題整理好了,大家可以在Java面試庫小程序在線刷題。?

          然后說一下Spring事務(wù)的回滾機(jī)制:

          Spring的AOP即聲明式事務(wù)管理默認(rèn)是針對unchecked exception回滾。Spring的事務(wù)邊界是在調(diào)用業(yè)務(wù)方法之前開始的,業(yè)務(wù)方法執(zhí)行完畢之后來執(zhí)行commit or rollback(Spring默認(rèn)取決于是否拋出runtimeException)。

          如果你在方法中有try{}catch(Exception e){}處理,那么try里面的代碼塊就脫離了事務(wù)的管理,若要事務(wù)生效需要在catch中throw new RuntimeException ("xxxxxx");這一點(diǎn)也是面試中會(huì)問到的事務(wù)失效的場景。

          再簡單介紹一下@Transactional注解底層實(shí)現(xiàn)方式吧,毫無疑問,是通過動(dòng)態(tài)代理,那么動(dòng)態(tài)代理又分為JDK自身和CGLIB,這個(gè)也不多贅述了,畢竟今天的主題是如何將@Transactional對于事物的控制應(yīng)用到爐火純青。哈哈~

          推薦一個(gè) Spring Boot 基礎(chǔ)實(shí)戰(zhàn)教程:
          https://github.com/javastacks/spring-boot-best-practice


          第一點(diǎn)要注意的就是在@Transactional注解的方法中,再調(diào)用本類中的其他方法method2時(shí),那么method2方法上的@Transactional注解是不!會(huì)!生!效!的!但是加上也并不會(huì)報(bào)錯(cuò),拿圖片簡單幫助理解一下吧。這一點(diǎn)也是面試中會(huì)問到的事務(wù)失效的場景。

          通過代理對象在目標(biāo)對象前后進(jìn)行方法增強(qiáng),也就是事務(wù)的開啟提交和回滾。那么繼續(xù)調(diào)用本類中其他方法是怎樣呢,如下圖:

          可見目標(biāo)對象內(nèi)部的自我調(diào)用,也就是通過this.指向的目標(biāo)對象將不會(huì)執(zhí)行方法的增強(qiáng)。


          先說第二點(diǎn)需要注意的地方,等下說如何解決上面第一點(diǎn)的問題。第二點(diǎn)就是@Transactional注解的方法必須是公共方法,就是必須是public修飾符!!!

          至于這個(gè)的原因,發(fā)表下個(gè)人的理解吧,因?yàn)镴VM的動(dòng)態(tài)代理是基于接口實(shí)現(xiàn)的,通過代理類將目標(biāo)方法進(jìn)行增強(qiáng),想一下也是啦,沒有權(quán)限訪問那么你讓我怎么進(jìn)行,,,好吧,這個(gè)我也沒有深入研究底層,個(gè)人理解個(gè)人理解。

          在這里我也放個(gè)問題吧,希望有高手可以回復(fù)指點(diǎn)指點(diǎn)我,因?yàn)镴VM動(dòng)態(tài)代理是基于接口實(shí)現(xiàn)的,那么是不是service層都要按照接口和實(shí)現(xiàn)類的開發(fā)模式,注解才會(huì)生效呢,就是說controller層直接調(diào)用沒有接口的service層,加了注解也一樣不起作用吧,這個(gè)懶了,沒有測試,其一是因?yàn)闆]有人會(huì)這么開發(fā)吧,其二是我就認(rèn)為是不起作用的,哈哈。

          下面來解決一下第一點(diǎn)的問題,如何在方法中調(diào)用本類中其他方法呢。

          通過AopContext.currentProxy ()獲取到本類的代理對象,再去調(diào)用就好啦。因?yàn)檫@個(gè)是CGLIB實(shí)現(xiàn),所以要開啟AOP,當(dāng)然也很簡單,在springboot啟動(dòng)類上加上注解@EnableAspectJAutoProxy(exposeProxy = true)就可以啦,這個(gè)依賴大家自行搜一下就好啦。要注意,注意,代理對象調(diào)用的方法也要是public修飾符,否則方法中獲取不到注入的bean,會(huì)報(bào)空指針錯(cuò)誤。

          emmmm,我先把調(diào)用的方式和結(jié)果說下吧。自己簡單寫了代碼,有點(diǎn)粗糙,就不要介意啦,嘿嘿。。。另外,最新 Spring 面試題整理好了,大家可以在Java面試庫小程序在線刷題。

          Controller中調(diào)用Service

          @RestController
          public class TransactionalController {

              @Autowired
              private TransactionalService transactionalService;

              @PostMapping("transactionalTest")
              public void transacionalTest(){
                  transactionalService.transactionalMethod();
              }
          }

          Service中實(shí)現(xiàn)對事務(wù)的控制:接口

          public interface TransactionalService {
              void transactionalMethod();
          }

          Service中實(shí)現(xiàn)對事務(wù)的控制:實(shí)現(xiàn)類(各種情況的說明都寫在圖片里了,這樣方便閱讀,有助于快速理解吧)

          上面兩種情況不管使不使用代理調(diào)用方法1和方法2,方法transactionalMethod都處在一個(gè)事務(wù)中,四條更新操作全部失敗。

          那么有人可能會(huì)有疑問了,在方法1和方法2上都加@Transactional注解呢?答案是結(jié)果和上面是一致的。

          小結(jié)只要方法transactionalMethod上有注解,并且方法1和方法2都處于當(dāng)前事務(wù)中(不使用代理調(diào)用,方法1和方法2上的@Transactional注解是不生效的;使用代理,需要方法1和方法2都處在transactionalMethod方法的事務(wù)中,默認(rèn)或者嵌套事務(wù)均可,當(dāng)然也可以不加@Transactional注解),那么整體保持事務(wù)一致性。

          如果想要方法1和方法2均單獨(dú)保持事務(wù)一致性怎么辦呢,剛說過了,如果不是用代理調(diào)用@Transactional注解是不生效的,所以一定要使用代理調(diào)用實(shí)現(xiàn),然后讓方法1和方法2分別單獨(dú)開啟新的事務(wù),便OK啦。下面擺上圖片。

          這兩種情況都是方法1和方法2均處在單獨(dú)的事務(wù)中,各自保持事務(wù)的一致性。

          接下來進(jìn)行進(jìn)一步的優(yōu)化,可以在transactionalMethod方法中分別對方法1和方法2進(jìn)行控制。要將代碼的藝術(shù)發(fā)揮到極致嘛,下面裝逼開始。

          代碼太長了,超過屏幕了,粘貼出來截的圖,紅框注釋需要仔細(xì)看,希望不要影響你的閱讀體驗(yàn),至此,本篇關(guān)于@Transactioinal注解的使用就到此為止啦,

          簡單總結(jié)一下吧:

          1、就是@Transactional注解保證的是每個(gè)方法處在一個(gè)事務(wù),如果有try一定在catch中拋出運(yùn)行時(shí)異常。

          2、方法必須是public修飾符。否則注解不會(huì)生效,但是加了注解也沒啥毛病,不會(huì)報(bào)錯(cuò),只是沒卵用而已。

          3、this.本方法的調(diào)用,被調(diào)用方法上注解是不生效的,因?yàn)闊o法再次進(jìn)行切面增強(qiáng)。

          如果有更細(xì)致的討論歡迎評論,感謝閱讀。

          版權(quán)聲明:本文為CSDN博主「范學(xué)博」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接及本聲明。原文鏈接:https://blog.csdn.net/fanxb92/article/details/81296005








          Spring Cloud Alibaba 終于一統(tǒng)江湖!
          Spring Boot 定時(shí)任務(wù)開啟后,怎么自動(dòng)停止?
          23 種設(shè)計(jì)模式實(shí)戰(zhàn)(很全)
          Spring Boot 保護(hù)敏感配置的 4 種方法!
          面了個(gè) 5 年 Java,兩個(gè)線程數(shù)據(jù)交換都不會(huì)
          阿里為什么推薦使用 LongAdder?
          新來一個(gè)技術(shù)總監(jiān):禁止戴耳機(jī)寫代碼。。
          別用 System... 計(jì)時(shí)了,StopWatch 好用到爆!
          Java 8 排序的 10 個(gè)姿勢,太秀了吧!
          Spring Boot Admin 橫空出世!
          Spring Boot 學(xué)習(xí)筆記,這個(gè)太全了!



          關(guān)注Java技術(shù)棧看更多干貨



          Spring Cloud Alibaba 最新實(shí)戰(zhàn)!
          瀏覽 44
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  黑鬼巨大两根一起挤进 | 操杨幂视频 | 操逼精品TV | 国产日韩欧美一级电影 | 日本网站在线播放 |