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)中,使用了控制復原的參數。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsISM9AnYldnJwAzN9c3Pn5GcuQ0MlQ0MlcnW1JkbMlXSU9UNrRVT3tGRNlHMD1UenRUT4FlaNNTR610drRUT1UERNlHMp5EMRpXTwMGVNZ3aE1UNFRUT5hTaOBTU61EMjRVT2NmMiNnSywEd5ITW110MaZHetlVdO1GT0UERNl3YXJGc5kHT20ESjBjUIF2Lc12bj5SYphXa5VWen5WY35iclN3Ztl2Lc9CX6MHc0RHaiojIsJye.png)
catch到異常具體怎麼辦?根據以上幾點規則,判斷異常類型與參數中聲明的類型關系決定。
事務組合控制參數
當一個作為事務的方法調用另一個作為事務的方法,它們之間的關系如何?這可以通過propagation參數控制。規則如下:
例如:
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異常。