天天看點

springboot--事務的使用 - 阿譯

springboot--事務的使用

@Transactional原理

        事務是一些sql語句對資料庫操作的集合,是以如果在一個Java方法裡涉及了對資料庫的操作,業務需要的話我們就可以考慮把這些操作作為一個事務。通過在方法上加個@Transactional(....)注解即可。

        如:

public class Transaction {

    @Transactional(....)
    public void doSomething() {
        .....
    }
}      

對于springboot,加了@Transactional的方法其實是這樣執行的:

BEGIN TRANSACTION;
try{
    doSomething();      //執行方法
    COMMIT;
}catch(Throwable t){
    if(t是該復原的異常)
        ROLLBACK;
     else 
        COMMIT;
}      

知道了注解的原理就好辦了,接下來隻需了解這個注解的參數即可應付很多業務場景。

控制復原參數

        rollbackFor = xx.class 表示抛出的異常是xx類及其子類,事務會復原; noRollbackFor = yy.class表示抛出異常是yy類或其子類,事務不會復原。在@Transactional(rollbackFor = xx.class , noRollbackFor = yy.class)中,使用了控制復原的參數。

springboot--事務的使用 - 阿譯

 catch到異常具體怎麼辦?根據以上幾點規則,判斷異常類型與參數中聲明的類型關系決定。

事務組合控制參數

        當一個作為事務的方法調用另一個作為事務的方法,它們之間的關系如何?這可以通過propagation參數控制。規則如下:

springboot--事務的使用 - 阿譯

 例如:

public class Transaction {

    @Autowired
    TransactionB b;
    
    @Transactional(propagation = Propagation.REQUIRED)
    public void methodA() {
       // 插入 id=1 的記錄
        b.methodB();
    }
}

class TransactionB {

     @Transactional(propagation = Propagation.REQUIRED)
    public void methodB() {
        // 插入 id=2 的記錄
    }
}      

1.methodB的注解參數  propagation = Propagation.REQUIRED 表示二者合并為同一個事務,id = 1,id = 2的記錄隻可能同時插入成功,或者同時插入失敗。

2.若methodB的注解參數  propagation = Propagation.REQUIRES_NEW 表示methodB的事務會被作為一個新事務,兩個事務之間沒有限制關系,是獨立的。                      id = 1,id = 2的記錄可能同時插入失敗/成功,也可能成功插入某一條。

3.若methodB的注解參數  propagation = Propagation.NESTED,表示methodB的事務是嵌套在methodA的事務中的,嵌套事務成功需要依賴主事務成功。反過來嵌套     事務則不會決定主事務的成功。即id = 1插入成功(主),id = 2(嵌套)不一定插入成功;id = 1插入失敗,id = 2則一定插入失敗。

事務隔離級别控制參數

        事務隔離級别的設定很簡單,直接@Transactional(isolation = xx)就可以指定方法中事務的隔離級别,隔離級别從低到高有:READ_UNCOMMITTED(讀未送出)、READ_COMMITTED(讀已送出)、REPEATABLE_READ(可重複讀)、SERIALIZABLE(串行化)。具體隔離級别以及每個隔離級别的意義這裡就不講了。

事務逾時控制參數

        timeout參數表示事務的時間限制,超出指定時間則抛出TransactionTimeOut異常。使用如下:

@Transactional(timeout = 5) //秒
    public void methodA() {     ---事務開始則計時開始
        // 1 執行java代碼         ---納入計時
        // 2 執行sql              ---執行前檢查是否逾時
        // 3 執行java代碼         ---納入計時
        // 4 執行sql              --執行前檢查是否逾時
        // 5 執行java代碼         ---由于sql執行完畢,事務已送出,這裡不被納入計時
    }      

注意:隻有每次執行sql前會檢查是否逾時,如果執行這個sql前沒逾時,就算這個sql執行了20s也不會抛出TransactionTimeOut異常。