Solon詳解(四)- Solon的事務傳播機制
阿新 • • 發佈:2020-08-22
Solon詳解系列文章:
Solon詳解(一)- 快速入門
Solon詳解(二)- Solon的核心
Solon詳解(三)- Solon的web開發
Solon詳解(四)- Solon的事務傳播機制
在前面的篇章裡我們已經見識了 Solon 對事務的控制,及其優雅曼妙的形態。該篇將對事務的傳播機制做講解。出於對使用者的學習成本考慮,Solon 借簽了Spring 的事務傳播策略;並友好的支援多資料來源事務。
一、為什麼要有傳播機制?
Solon 的事務是基於 aop 實現的,用者不用關心事務的開始、提交、回滾,只需要在方法上加 @XTran 註解。因為看不到內部情況,所以也會有些疑問:
- 場景一:方法A呼叫了方法B,但兩個方法都有事務,這個時候如果方法B異常:
- 是讓方法B回滾,還是兩個一起回滾?
- 場景二:方法A呼叫了方法B,但是隻有方法A加了事務:
- 是否讓方法B也加入方法A的事務?
- 如果方法B異常,是否回滾方法A?
- 場景三:方法A呼叫了方法B,兩者都有事務,方法B已經正常執行完:
- 但方法A異常,是否需要回滾方法B的資料?
這個時候事務的傳播機制和策略就派上用場了。
二、傳播機制生效條件與特點!
基於 aop 來代理事務控制的方案 ,大都是針對於介面或類的之間呼叫才起效的;所以在同一個類中兩個方法之間的呼叫,傳播機制是無效的。瞭解這一點很重要,不然容易出烏龍事件。
- 特點1:Solon 的事務傳播策略與Spring差不多(出於對新使用者的學習成本考慮)
- 特點2:Solon 可方便的支援多資料來源事務
- 特點3:Solon 可方便支援分庫框架或中介軟體的事務
三、傳播機制的策略
下面的型別都是針對於被呼叫方法來說的,理解起來要想象成兩個 service 方法的呼叫才可以。
傳番策略 | 說明 |
---|---|
@XTran(group=true) | 如果當前沒有事務組,則新建一個事務組;可用於管理多資料來源事務,但不會建立連結 |
@XTran(policy=TranPolicy.required) | 如果當前沒有事務,就新建一個事務,如果已經存在一個事務中,加入到這個事務中。這是最常見的選擇。也是預設。 |
@XTran(policy=TranPolicy.requires_new) | 新建事務,如果當前存在事務,把當前事務掛起。 |
@XTran(policy=TranPolicy.nested) | 如果當前存在事務,則在巢狀事務內執行。如果當前沒有事務,則執行與required類似的操作。 |
@XTran(policy=TranPolicy.mandatory) | 使用當前的事務,如果當前沒有事務,就丟擲異常。 |
@XTran(policy=TranPolicy.supports) | 支援當前事務,如果當前沒有事務,就以非事務方式執行。 |
@XTran(policy=TranPolicy.not_supported) | 以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。 |
@XTran(policy=TranPolicy.never) | 以非事務方式執行,如果當前存在事務,則丟擲異常。 |
- 補充1:如果當前為事務組,required 和 nested 策略的事務,會自動加入事務組
- 補充2:group=true 有時候可當 required 用
- 補充3:一般最常用的是 @XTran(group = true) 和 @Tran 的組合使用
四、XTran 屬性說明
屬性 | 說明 |
---|---|
value | 資料來源標識 |
policy | 事務策略 |
group | 是否為事務組;用於管理下屬的子事務 |
五、示例
- 父回滾,子回滾
@XService
public class UserService{
@XTran
public void addUser(UserModel user){
//....
}
}
@XController
public class DemoController{
@XInject
UserService userService;
//父回滾,子回滾
//
@XTran(group = true)
@XMapping("/user/add")
pubblic void addUser(UserModel user){
userService.addUser(user);
throw new RuntimeException("不讓你加");
}
//父回滾,子回滾
//
@XTran
@XMapping("/user/add2")
pubblic void addUser2(UserModel user){
userService.addUser(user);
throw new RuntimeException("不讓你加");
}
}
- 父回滾,子不回滾
@XService
public class UserService{
@XTran(policy = TranPolicy.requires_new)
public void addUser(UserModel user){
//....
}
}
@XController
public class DemoController{
@XInject
UserService userService;
//父回滾,子不回滾
//
@XTran(group = true)
@XMapping("/user/add")
pubblic void addUser(UserModel user){
userService.addUser(user);
throw new RuntimeException("不讓你加;但還是加了:(");
}
//父回滾,子不回滾
//
@XTran
@XMapping("/user/add2")
pubblic void addUser2(UserModel user){
userService.addUser(user);
throw new RuntimeException("不讓你加;但還是加了:(");
}
}
- 子回滾父不回滾
@XService
public class UserService{
@XTran(policy = TranPolicy.nested)
public void addUser(UserModel user){
//....
throw new RuntimeException("不讓你加");
}
}
@XController
public class DemoController{
@XInject
UserService userService;
//子回滾父不回滾
//
@XTran(group = true)
@XMapping("/user/add")
pubblic void addUser(UserModel user){
try{
userService.addUser(user);
}catch(ex){ }
}
//子回滾父不回滾
//
@XTran
@XMapping("/user/add2")
pubblic void addUser2(UserModel user){
try{
userService.addUser(user);
}catch(ex){ }
}
}
- 多資料來源事務示例
@XService
public class UserService{
@XTran("db1")
public void addUser(UserModel user){
//....
}
}
@XService
public class AccountService{
@XTran("db2")
public void addAccount(UserModel user){
//....
}
}
@XController
public class DemoController{
@XInject
AccountService accountService;
@XInject
UserService userService;
@XTran(group = true)
@XMapping("/user/add")
pubblic void addUser(UserModel user){
userService.addUser(user); //會執行db1事務
accountService.addAccount(user); //會執行db2事務
}
}