對Spring事務一些問題的討論

  提起spring事務,就會讓人聯想起四大基本特徵,五個隔離級別,七大傳播特性。相信大多數人都知道這些東西,可是知道是一回事情,能用好真的是另外一回事了。在使用Spring事務的時候,我曾遇到過幾個比較嚴肅的問題,在這裏我作一個自我總結。

 

問題1、 propagation.NESTED和propagation.REQUIRED_NEW有什麼區別?

  當調用方不存在事務的時候,二者的效果是一致的。因此這裏討論問題的前提是調用方存在事務。PROPAGATION_REQUIRES_NEW 啓動一個新的, 不依賴於環境的 "內部" 事務. 這個事務將被徹底 commited 或 rolled back 而不依賴於外部事務, 它擁有本身的隔離範圍, 本身的鎖, 等等. 當內部事務開始執行時, 外部事務將被掛起, 內務事務結束時, 外部事務將繼續執行. 
另外一方面, PROPAGATION_NESTED 開始一個 "嵌套的" 事務, 它是已經存在事務的一個真正的子事務. 潛套事務開始執行時, 它將取得一個 savepoint. 若是這個嵌套事務失敗, 咱們將回滾到此 savepoint. 潛套事務是外部事務的一部分, 只有外部事務結束後它纔會被提交. 
因而可知, PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大區別在於, PROPAGATION_REQUIRES_NEW 徹底是一個新的事務, 而 PROPAGATION_NESTED 則是外部事務的子事務, 若是外部事務 commit, 嵌套事務也會被 commit, 這個規則一樣適用於 roll back. spring

 

問題2、 @Transactional爲何會失效?

  1.調用方和被調用方屬於同一個component,被調用方的 @Transacational註解無效sql

  

package com.transacational;

import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

/**
 * Created by chenqimiao on 17/10/31.
 */
@Component
public class Service {

    public void test1(){
        test2();
    }

    @Transactional//此處的註解無效
    public void test2(){

    }
}

 

  2.被調用方不是一個public方法,被調用方的 @Transacational註解無效  app

@Component
public class Service {

    @Resource
    private Service1 service1;
    
    public void test1(){
        test2();
        service1.test3();
    }

    @Transactional//1.此處的註解無效
    public void test2(){

    }
}

 

package com.transacational;

import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

/**
 * Created by chenqimiao on 17/10/31.
 */
@Component
public class Service1 {

    @Transactional//2.此處註解無效
    protected void test3(){

    }
}

 

  

  3.未開啓事務開關,如:在SpringBoot中,啓動類未使用 @EnableTransactionManagementspa

 

 

問題3、 如何理解@Transactional的超時時間?

   timeout是一個供開發者設置超時時間的屬性。默認值-1,超時時間由具體的sql系統決定。   code

/**
 * Created by chenqimiao on 17/10/31.
 */
@Component
public class Service3 {


    @Resource
    private AdminInfoDoMapper adminInfoDoMapper;
    @Transactional(timeout = 4)//並不會超時
    public void test4(){

        adminInfoDoMapper.selectNameById(1);
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 

超時時間具體的定義:事務開始(在該方法第一句代碼執行以前)到最後一個Statement執行完畢component

因此象下面這樣寫,事務就會超時blog

@Component
public class Service3 {


    @Resource
    private AdminInfoDoMapper adminInfoDoMapper;
    @Transactional(timeout = 4)
    public void test4(){
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        adminInfoDoMapper.selectNameById(1);

    }
}

 

 

 

問題4、 @Transactional默認的回滾策略?

默認狀況下,只有當RuntimeException或其子類的異常被事務捕獲以後,事務纔會回滾,若是要讓事務可以回滾全部異常,必須手動指定  @Transactional(rollbackFor=Exception.class)  ,這樣繼承Exception的子類或者Exception自己均可以讓事務回滾。繼承

相關文章
相關標籤/搜索