Springboot min -Solon 詳解系列文章:
Springboot mini - Solon詳解(一)- 快速入門
Springboot mini - Solon詳解(二)- Solon的核心
Springboot mini - Solon詳解(三)- Solon的web開發
在前面的篇章裡我們已經見識了 Springboot mini - Solon 對事務的控制,及其優雅曼妙的身姿。該篇將對事務及其處理策略進行詳解。出於對使用者的學習成本考慮,Solon 借簽了Spring 的事務傳播策略;所以體驗上幾乎一樣。
一、為什麼要有傳播機制?
Solon 對事務的控制,是使用 aop 切面實現的,所以不用關心事務的開始,提交 ,回滾,只需要在方法上加 @Tran
註解即可。
因為這些都是暗的,看不見的,所以也容易產生一些疑惑:
- 場景一:classA 方法呼叫了 classB 方法,但兩個方法都有事務
如果 classB 方法異常,是讓 classB 方法提交,還是兩個一起回滾?
- 場景二:classA 方法呼叫了 classB 方法,但是隻有 classA 方法加了事務
是否把 classB 也加入 classA 的事務,如果 classB 異常,是否回滾 classA?
- 場景三:classA 方法呼叫了 classB 方法,兩者都有事務,classB 已經正常執行完,但 classA 異常
是否需要回滾 classB 的資料?
這個時候,傳說中的事務傳播機制和策略就派上用場了
二、傳播機制生效條件
所有用 aop 實現的事務控制方案 ,都是針對於介面或類的。所以在同一個類中兩個方法的呼叫,傳播機制是不生效的。
三、傳播機制的策略
下面的型別都是針對於被呼叫方法來說的,理解起來要想象成兩個 class 方法的呼叫才可以。
傳番策略 | 說明 |
---|---|
TranPolicy.required | 支援當前事務,如果沒有則建立一個新的。這是最常見的選擇。也是預設。 |
TranPolicy.requires_new | 新建事務,如果當前存在事務,把當前事務掛起。 |
TranPolicy.nested | 如果當前有事務,則在當前事務內部巢狀一個事務;否則新建事務。 |
TranPolicy.mandatory | 支援當前事務,如果沒有事務則報錯。 |
TranPolicy.supports | 支援當前事務,如果沒有則不使用事務。 |
TranPolicy.not_supported | 以無事務的方式執行,如果當前有事務則將其掛起。 |
TranPolicy.never | 以無事務的方式執行,如果當前有事務則報錯。 |
四、事務的隔離級別
屬性 | 說明 |
---|---|
unspecified | 預設(JDBC預設) |
read_uncommitted | 髒讀:其它事務,可讀取未提交資料 |
read_committed | 只讀取提交資料:其它事務,只能讀取已提交資料 |
repeatable_read | 可重複讀:保證在同一個事務中多次讀取同樣資料的結果是一樣的 |
serializable | 可序列化讀:要求事務序列化執行,事務只能一個接著一個執行,不能併發執行 |
五、@Tran 屬性說明
屬性 | 說明 |
---|---|
policy | 事務傳導策略 |
isolation | 事務隔離等級 |
readOnly | 是否為只讀事務 |
六、示例
- 父回滾,子回滾
@Service
public class UserService{
@Tran
public void addUser(UserModel user){
//....
}
}
@Controller
public class DemoController{
@Inject
UserService userService;
//父回滾,子回滾
//
@Tran
@Mapping("/user/add2")
pubblic void addUser2(UserModel user){
userService.addUser(user);
throw new RuntimeException("不讓你加");
}
}
- 父回滾,子不回滾
@Service
public class UserService{
@Tran(policy = TranPolicy.requires_new)
public void addUser(UserModel user){
//....
}
}
@Controller
public class DemoController{
@Inject
UserService userService;
//父回滾,子不回滾
//
@Tran
@Mapping("/user/add2")
pubblic void addUser2(UserModel user){
userService.addUser(user);
throw new RuntimeException("不讓你加;但還是加了:(");
}
}
- 子回滾父不回滾
@Service
public class UserService{
@Tran(policy = TranPolicy.nested)
public void addUser(UserModel user){
//....
throw new RuntimeException("不讓你加");
}
}
@Controller
public class DemoController{
@Inject
UserService userService;
//子回滾父不回滾
//
@Tran
@Mapping("/user/add2")
pubblic void addUser2(UserModel user){
try{
userService.addUser(user);
}catch(ex){ }
}
}
- 多資料來源事務示例
@Service
public class UserService{
@Db("db1")
UserMapper userDao;
@Tran
public void addUser(UserModel user){
userDao.insert(user);
}
}
@Service
public class AccountService{
@Db("db2")
AccountMappeer accountDao;
@Tran
public void addAccount(UserModel user){
accountDao.insert(user);
}
}
@Controller
public class DemoController{
@Inject
AccountService accountService;
@Inject
UserService userService;
@Tran
@Mapping("/user/add")
public void addUser(UserModel user){
userService.addUser(user); //會執行db1事務
accountService.addAccount(user); //會執行db2事務
}
}
附:Solon專案地址
- gitee: https://gitee.com/noear/solon
- github: https://github.com/noear/solon