<kbd id="5sdj3"></kbd>
<th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>

    Spring 事務(wù)底層原理

    共 6574字,需瀏覽 14分鐘

     ·

    2022-12-17 13:34

    • @EnableTransactionManagement工作原理
    • Spring事務(wù)基本執(zhí)行原理
    • Spring事務(wù)詳細(xì)執(zhí)行流程
    • Spring事務(wù)傳播機(jī)制
    • Spring事務(wù)傳播機(jī)制分類
      • 案例分析
      • 情況1
      • 情況2
      • 情況3
      • 情況4
    • Spring事務(wù)強(qiáng)制回滾
    • TransactionSynchronization


    一、@EnableTransactionManagement工作原理


    開啟Spring事務(wù)本質(zhì)上就是增加了一個(gè)Advisor,但我們使用@EnableTransactionManagement注解來開啟Spring事務(wù)是,該注解代理的功能就是向Spring容器中添加了兩個(gè)Bean:

    • AutoProxyRegistrar
    • ProxyTransactionManagementConfiguration

    AutoProxyRegistrar主要的作用是向Spring容器中注冊(cè)了一個(gè)InfrastructureAdvisorAutoProxyCreator的Bean。而InfrastructureAdvisorAutoProxyCreator繼承了AbstractAdvisorAutoProxyCreator,所以這個(gè)類的主要作用就是開啟自動(dòng)代理的作用,也就是一個(gè)BeanPostProcessor,會(huì)在初始化后步驟中去尋找Advisor類型的Bean,并判斷當(dāng)前某個(gè)Bean是否有匹配的Advisor,是否需要利用動(dòng)態(tài)代理產(chǎn)生一個(gè)代理對(duì)象。

    ProxyTransactionManagementConfiguration是一個(gè)配置類,它又定義了另外三個(gè)bean:

    • BeanFactoryTransactionAttributeSourceAdvisor:一個(gè)Advisor
    • AnnotationTransactionAttributeSource:相當(dāng)于BeanFactoryTransactionAttributeSourceAdvisor中的Pointcut
    • TransactionInterceptor:相當(dāng)于BeanFactoryTransactionAttributeSourceAdvisor中的Advice

    AnnotationTransactionAttributeSource就是用來判斷某個(gè)類上是否存在@Transactional注解,或者判斷某個(gè)方法上是否存在@Transactional注解的。

    TransactionInterceptor就是代理邏輯,當(dāng)某個(gè)類中存在@Transactional注解時(shí),到時(shí)就產(chǎn)生一個(gè)代理對(duì)象作為Bean,代理對(duì)象在執(zhí)行某個(gè)方法時(shí),最終就會(huì)進(jìn)入到TransactionInterceptor的invoke()方法。


    二、Spring事務(wù)基本執(zhí)行原理


    一個(gè)Bean在執(zhí)行Bean的創(chuàng)建生命周期時(shí),會(huì)經(jīng)過InfrastructureAdvisorAutoProxyCreator的初始化后的方法,會(huì)判斷當(dāng)前Bean對(duì)象是否和BeanFactoryTransactionAttributeSourceAdvisor匹配,匹配邏輯為判斷該Bean的類上是否存在@Transactional注解,或者類中的某個(gè)方法上是否存在@Transactional注解,如果存在則表示該Bean需要進(jìn)行動(dòng)態(tài)代理產(chǎn)生一個(gè)代理對(duì)象作為Bean對(duì)象。

    該代理對(duì)象在執(zhí)行某個(gè)方法時(shí),會(huì)再次判斷當(dāng)前執(zhí)行的方法是否和BeanFactoryTransactionAttributeSourceAdvisor匹配,如果匹配則執(zhí)行該Advisor中的TransactionInterceptor的invoke()方法,執(zhí)行基本流程為:

    1. 利用所配置的PlatformTransactionManager事務(wù)管理器新建一個(gè)數(shù)據(jù)庫連接
    2. 修改數(shù)據(jù)庫連接的autocommit為false
    3. 執(zhí)行MethodInvocation.proceed()方法,簡(jiǎn)單理解就是執(zhí)行業(yè)務(wù)方法,其中就會(huì)執(zhí)行sql
    4. 如果沒有拋異常,則提交
    5. 如果拋了異常,則回滾


    三、Spring事務(wù)詳細(xì)執(zhí)行流程


    Spring事務(wù)執(zhí)行流程圖:https://www.processon.com/view/link/5fab6edf1e0853569633cc06

    四、Spring事務(wù)傳播機(jī)制


    在開發(fā)過程中,經(jīng)常會(huì)出現(xiàn)一個(gè)方法調(diào)用另外一個(gè)方法,那么這里就涉及到了多種場(chǎng)景,比如a()調(diào)用b():
    • a()和b()方法中的所有sql需要在同一個(gè)事務(wù)中嗎?
    • a()和b()方法需要單獨(dú)的事務(wù)嗎?
    • a()需要在事務(wù)中執(zhí)行,b()還需要在事務(wù)中執(zhí)行嗎?
    • 等等情況…
    所以,這就要求Spring事務(wù)能支持上面各種場(chǎng)景,這就是Spring事務(wù)傳播機(jī)制的由來。那Spring事務(wù)傳播機(jī)制是如何實(shí)現(xiàn)的呢?
    先來看上述幾種場(chǎng)景中的一種情況,a()在一個(gè)事務(wù)中執(zhí)行,調(diào)用b()方法時(shí)需要新開一個(gè)事務(wù)執(zhí)行:
    • 首先,代理對(duì)象執(zhí)行a()方法前,先利用事務(wù)管理器新建一個(gè)數(shù)據(jù)庫連接a
    • 將數(shù)據(jù)庫連接a的autocommit改為false
    • 把數(shù)據(jù)庫連接a設(shè)置到ThreadLocal中
    • 執(zhí)行a()方法中的sql
    • 執(zhí)行a()方法過程中,調(diào)用了b()方法(注意用代理對(duì)象調(diào)用b()方法)
      • 代理對(duì)象執(zhí)行b()方法前,判斷出來了當(dāng)前線程中已經(jīng)存在一個(gè)數(shù)據(jù)庫連接a了,表示當(dāng)前線程其實(shí)已經(jīng)擁有一個(gè)Spring事務(wù)了,則進(jìn)行掛起
      • 掛起就是把ThreadLocal中的數(shù)據(jù)庫連接a從ThreadLocal中移除,并放入一個(gè)掛起資源對(duì)象中
      • 掛起完成后,再次利用事務(wù)管理器新建一個(gè)數(shù)據(jù)庫連接b
      • 將數(shù)據(jù)庫連接b的autocommit改為false
      • 把數(shù)據(jù)庫連接b設(shè)置到ThreadLocal中
      • 執(zhí)行b()方法中的sql
      • b()方法正常執(zhí)行完,則從ThreadLocal中拿到數(shù)據(jù)庫連接b進(jìn)行提交
      • 提交之后會(huì)恢復(fù)所掛起的數(shù)據(jù)庫連接a,這里的恢復(fù),其實(shí)只是把在掛起資源對(duì)象中所保存的數(shù)據(jù)庫連接a再次設(shè)置到ThreadLocal中
    • a()方法正常執(zhí)行完,則從ThreadLocal中拿到數(shù)據(jù)庫連接a進(jìn)行提交
    這個(gè)過程中最為核心的是:在執(zhí)行某個(gè)方法時(shí),判斷當(dāng)前是否已經(jīng)存在一個(gè)事務(wù),就是判斷當(dāng)前線程的ThreadLocal中是否存在一個(gè)數(shù)據(jù)庫連接對(duì)象,如果存在則表示已經(jīng)存在一個(gè)事務(wù)了。


    五、Spring事務(wù)傳播機(jī)制分類


    其中,以非事務(wù)方式運(yùn)行,表示以非Spring事務(wù)運(yùn)行,表示在執(zhí)行這個(gè)方法時(shí),Spring事務(wù)管理器不會(huì)去建立數(shù)據(jù)庫連接,執(zhí)行sql時(shí),由Mybatis或JdbcTemplate自己來建立數(shù)據(jù)庫連接來執(zhí)行sql。
    案例分析

    情況1

    @Componentpublic class UserService { @Autowired private UserService userService;
    @Transactional public void test() { // test方法中的sql userService.a(); }
    @Transactional public void a() { // a方法中的sql }}
    默認(rèn)情況下傳播機(jī)制為REQUIRED,表示當(dāng)前如果沒有事務(wù)則新建一個(gè)事務(wù),如果有事務(wù)則在當(dāng)前事務(wù)中執(zhí)行。
    所以上面這種情況的執(zhí)行流程如下:
    1. 新建一個(gè)數(shù)據(jù)庫連接conn
    2. 設(shè)置conn的autocommit為false
    3. 執(zhí)行test方法中的sql
    4. 執(zhí)行a方法中的sql
    5. 執(zhí)行conn的commit()方法進(jìn)行提交
    情況2

    假如是這種情況:

    @Componentpublic class UserService { @Autowired private UserService userService;
    @Transactional public void test() { // test方法中的sql userService.a(); int result = 100/0; }
    @Transactional public void a() { // a方法中的sql }}

    所以上面這種情況的執(zhí)行流程如下:

    1. 新建一個(gè)數(shù)據(jù)庫連接conn
    2. 設(shè)置conn的autocommit為false
    3. 執(zhí)行test方法中的sql
    4. 執(zhí)行a方法中的sql
    5. 拋出異常
    6. 執(zhí)行conn的rollback()方法進(jìn)行回滾,所以兩個(gè)方法中的sql都會(huì)回滾掉

    情況3

    假如是這種情況:

    @Componentpublic class UserService { @Autowired private UserService userService;
    @Transactional public void test() { // test方法中的sql userService.a(); }
    @Transactional public void a() { // a方法中的sql int result = 100/0; }}
    所以上面這種情況的執(zhí)行流程如下:
    1. 新建一個(gè)數(shù)據(jù)庫連接conn
    2. 設(shè)置conn的autocommit為false
    3. 執(zhí)行test方法中的sql
    4. 執(zhí)行a方法中的sql
    5. 拋出異常
    6. 執(zhí)行conn的rollback()方法進(jìn)行回滾,所以兩個(gè)方法中的sql都會(huì)回滾掉

    情況4

    如果是這種情況:

    @Componentpublic class UserService { @Autowired private UserService userService;
    @Transactional public void test() { // test方法中的sql userService.a(); }
    @Transactional(propagation = Propagation.REQUIRES_NEW) public void a() { // a方法中的sql int result = 100/0; }}

    所以上面這種情況的執(zhí)行流程如下:

    1. 新建一個(gè)數(shù)據(jù)庫連接conn
    2. 設(shè)置conn的autocommit為false
    3. 執(zhí)行test方法中的sql
    4. 又新建一個(gè)數(shù)據(jù)庫連接conn2
    5. 執(zhí)行a方法中的sql
    6. 拋出異常
    7. 執(zhí)行conn2的rollback()方法進(jìn)行回滾
    8. 繼續(xù)拋異常,對(duì)于test()方法而言,它會(huì)接收到一個(gè)異常,然后拋出
    9. 執(zhí)行conn的rollback()方法進(jìn)行回滾,最終還是兩個(gè)方法中的sql都回滾了


    六、Spring事務(wù)強(qiáng)制回滾


    正常情況下,a()調(diào)用b()方法時(shí),如果b()方法拋了異常,但是在a()方法捕獲了,那么a()的事務(wù)還是會(huì)正常提交的,但是有的時(shí)候,我們捕獲異??赡軆H僅只是不把異常信息返回給客戶端,而是為了返回一些更友好的錯(cuò)誤信息,而這個(gè)時(shí)候,我們還是希望事務(wù)能回滾的,那這個(gè)時(shí)候就得告訴Spring把當(dāng)前事務(wù)回滾掉,做法就是:
    @Transactionalpublic void test(){
    // 執(zhí)行sql try { b(); } catch (Exception e) { // 構(gòu)造友好的錯(cuò)誤信息返回 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); }
    }
    public void b() throws Exception { throw new Exception();}


    七、TransactionSynchronization


    Spring事務(wù)有可能會(huì)提交,回滾、掛起、恢復(fù),所以Spring事務(wù)提供了一種機(jī)制,可以讓程序員來監(jiān)聽當(dāng)前Spring事務(wù)所處于的狀態(tài)。
    @Componentpublic class UserService {
    @Autowired private JdbcTemplate jdbcTemplate;
    @Autowired private UserService userService;
    @Transactional public void test(){ TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
    @Override public void suspend() { System.out.println("test被掛起了"); }
    @Override public void resume() { System.out.println("test被恢復(fù)了"); }
    @Override public void beforeCommit(boolean readOnly) { System.out.println("test準(zhǔn)備要提交了"); }
    @Override public void beforeCompletion() { System.out.println("test準(zhǔn)備要提交或回滾了"); }
    @Override public void afterCommit() { System.out.println("test提交成功了"); }
    @Override public void afterCompletion(int status) { System.out.println("test提交或回滾成功了"); } });
    jdbcTemplate.execute("insert into t1 values(1,1,1,1,'1')"); System.out.println("test"); userService.a(); }
    @Transactional(propagation = Propagation.REQUIRES_NEW) public void a(){ TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
    @Override public void suspend() { System.out.println("a被掛起了"); }
    @Override public void resume() { System.out.println("a被恢復(fù)了"); }
    @Override public void beforeCommit(boolean readOnly) { System.out.println("a準(zhǔn)備要提交了"); }
    @Override public void beforeCompletion() { System.out.println("a準(zhǔn)備要提交或回滾了"); }
    @Override public void afterCommit() { System.out.println("a提交成功了"); }
    @Override public void afterCompletion(int status) { System.out.println("a提交或回滾成功了"); } });
    jdbcTemplate.execute("insert into t1 values(2,2,2,2,'2')"); System.out.println("a"); }
    }

    推薦閱讀:

    世界的真實(shí)格局分析,地球人類社會(huì)底層運(yùn)行原理

    不是你需要中臺(tái),而是一名合格的架構(gòu)師(附各大廠中臺(tái)建設(shè)PPT)

    企業(yè)IT技術(shù)架構(gòu)規(guī)劃方案

    論數(shù)字化轉(zhuǎn)型——轉(zhuǎn)什么,如何轉(zhuǎn)?

    華為干部與人才發(fā)展手冊(cè)(附PPT)

    企業(yè)10大管理流程圖,數(shù)字化轉(zhuǎn)型從業(yè)者必備!

    【中臺(tái)實(shí)踐】華為大數(shù)據(jù)中臺(tái)架構(gòu)分享.pdf

    華為的數(shù)字化轉(zhuǎn)型方法論

    華為如何實(shí)施數(shù)字化轉(zhuǎn)型(附PPT)

    超詳細(xì)280頁Docker實(shí)戰(zhàn)文檔!開放下載

    華為大數(shù)據(jù)解決方案(PPT)


    瀏覽 46
    點(diǎn)贊
    評(píng)論
    收藏
    分享

    手機(jī)掃一掃分享

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

    手機(jī)掃一掃分享

    分享
    舉報(bào)

    <kbd id="5sdj3"></kbd>
    <th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>
    操屄的免费视频 | 影音先锋东京热 | 国产精品无码在线观看视频 | 99热18| 黄色片在线 |