網(wǎng)站首頁 編程語言 正文
Spring 事務(wù)失效指在使用 Spring 進(jìn)行事務(wù)管理時,事務(wù)沒有被正確地提交或回滾所致的問題。可能是因為代碼中未正確地配置事務(wù)管理器或者事務(wù)注解的使用不正確所導(dǎo)致的。如果事務(wù)失效,則數(shù)據(jù)庫操作可能未能正確地更新或回滾,可能會造成不可預(yù)知的結(jié)果,從而影響系統(tǒng)的穩(wěn)定性和一致性。
1. 訪問權(quán)限問題
Java 的訪問權(quán)限有4種:private
、default
、protected
、public
,它們的權(quán)限從左到右,以此變大。如果在開發(fā)中,將事務(wù)方法定義了錯誤的訪問權(quán)限,則事務(wù)功能會失效。
@Service
public class EmpService {
@Transactional
private void add(UserModel userModel){
saveData(userModel);
}
}
如上:add 方法的權(quán)限被定義成了?private
,這樣會導(dǎo)致事務(wù)失效,Spring 要求被代理方法必須是public
的。
在Spring源碼中,如果目標(biāo)方法不是?
public
,則?TransactionAttribute?
返回 null,不支持事務(wù)。
2. 方法被 final 修飾
方法被final
修飾時,也會導(dǎo)致事務(wù)失效,如下的add方法使用了final
修飾,造成事務(wù)失效。
@Service
public class EmpService {
@Transactional
public final void add(UserModel userModel){
saveData(userModel);
}
}
因為 Spring 事務(wù)底層是用了 AOP ,用了JDK的動態(tài)代理或者CGLB的動態(tài)代理,會幫我們生成代理類,在代理類中實現(xiàn)事務(wù)功能。如果某個方法被final修飾了,那么在代理類中,就無法重新該方法,而添加事務(wù)功能。
注意:如果某個方法被static修飾,同樣也無法通過動態(tài)代理,變成事務(wù)方法。
3. 直接調(diào)用內(nèi)部方法
@Service
public class EmpService {
public void add(UserModel userModel){
saveData(userModel);
updateSataus(userModel);
}
@Transactional
public void updateSataus(UserModel userModel){
doSomething();
}
}
在事務(wù)方法add可知,它直接調(diào)用了 updateStatus 方法,方法擁有事務(wù)的能力是因為 Spring AOP 中生成了代理對象,但是直接調(diào)用 updateStatus 方法不會直接生成事務(wù)。但是可以直接將該類直接注入進(jìn)來,比如:
@Service
public class EmpService {
private EmpService empService;
@Transactional
public void add(UserModel userModel){
saveData(userModel);
empService.updateSataus(userModel);
}
@Transactional(rollbackFor = Exception.class)
public void updateSataus(UserModel userModel){
doSomething();
}
}
這樣事務(wù)就生效了,也不會穿生循環(huán)依賴的問題。
4. 未被 Spring 管理
如下所示:EmpService 類沒有交給 Spring 進(jìn)行管理(沒添加@Service
等注解),導(dǎo)致事務(wù)失效。
public class EmpService {
@Transactional
public void add(UserModel userModel){
saveData(userModel);
updateSataus(userModel);
}
}
5. 多線程調(diào)用
由以下代碼可知:在 add 事務(wù)方法里面,調(diào)用了 updateStatus 事務(wù)方法,但是 updateStatus 事務(wù)方法是在另外一個線程中調(diào)用的。這樣就導(dǎo)致了兩個方法不在同一個線程中,獲取到了數(shù)據(jù)庫連接不一樣,從而是兩個不同的事務(wù),如果 updateStatus 方法中拋出了異常,add 方法是不會回滾的。
@Service
public class EmpService {
@Autowired
private OrderService orderService;
@Transactional
public void add(UserModel userModel){
new Thread(()->{
orderService.updateSataus();
}).start();
}
}
@Service
public class OrderService{
@Transactional
public void updateSataus(){
System.out.println("======================");
}
}
Spring的事務(wù)是通過數(shù)據(jù)庫的連接來實現(xiàn)的:
當(dāng)前線程中保存了一個 map,key 是數(shù)據(jù)源,value 是數(shù)據(jù)庫連接。同一個事務(wù),指同一個數(shù)據(jù)庫連接,只有擁有同一個事務(wù)連接才能保證同時提交和回滾。如果是不同的線程,拿到的數(shù)據(jù)庫連接肯定是不同的。
6. 數(shù)據(jù)庫不支持事務(wù)
如果數(shù)據(jù)庫的引擎是myisam
,那么它是不支持事務(wù)的,要想支持事務(wù),改成innodb
引擎
7. 事務(wù)沒有開啟
如果是 Spring Boot 項目,那么是事務(wù)默認(rèn)是開啟的,但如果是 Spring 項目,需要 xml 配置
8. 事務(wù)的傳播特性
如果事務(wù)的傳播特性設(shè)置錯了,事務(wù)也會失效
如下:Propagation.NEVER
這種類型的傳播特性不支持事務(wù),如果有事務(wù)會拋出異常。
@Service
public class EmpService {
//Propagation.NEVER傳播特性不支持事務(wù)
@Transactional(propagation = Propagation.NEVER)
public void add(UserModel userModel){
saveData(userModel);
updateSataus(userModel);
}
}
目前只有這三種傳播特性才會創(chuàng)建新事物:REQUIRED
、REQUIRES_NEW
、NESTED
9. 自己捕獲了異常
事務(wù)不會回滾,最常見的問題是:開發(fā)者在代碼中手動try...catch了異常
@Service
public class EmpService {
@Transactional
public void add(UserModel userModel){
try {//開發(fā)者手動捕獲了異常,導(dǎo)致事務(wù)失效
saveData(userModel);
updateSataus(userModel);
} catch (Exception e) {
e.printStackTrace();
}
}
}
10. 手動拋了別的異常
如果拋的異常不正確,事務(wù)也不會回滾
@Service
public class EmpService {
@Transactional
public void add(UserModel userModel) throws Exception {
try {
saveData(userModel);
updateSataus(userModel);
} catch (Exception e) {
throw new Exception(e);
}
}
}
因為 Spring 事務(wù),默認(rèn)情況下只會回滾RuntimeException(運行時異常)
和Error(錯誤)
,對于普通的非運行時異常,它不會回滾。
11. 自定義回滾異常
如果在使用@Transactional
注解聲明事務(wù)時,有時想自定義回滾異常,Spring 也是支持的。可以通過設(shè)置rollbackFor
參數(shù),來完成這個功能。如下:
@Service
public class EmpService {
@Transactional(rollbackFor = BusinessException.class)
public void add(UserModel userModel) {
saveData(userModel);
updateSataus(userModel);
}
}
但是如果在程序執(zhí)行過程中,出現(xiàn)了 SQL 異常,但是 SQL 異常并不屬于我們定義的 BusinessException
異常,所以事務(wù)也不會回滾
原文鏈接:https://blog.csdn.net/Mr_VK/article/details/136438383
- 上一篇:沒有了
- 下一篇:沒有了
相關(guān)推薦
- 2023-08-01 TypeScript 中的字面量類型和聯(lián)合類型特性
- 2022-05-22 C++設(shè)計模式中的橋模式你了解嗎_C 語言
- 2022-06-18 Android?Scroller實現(xiàn)彈性滑動效果_Android
- 2022-10-01 使用301永久重定向和302臨時重定向作用區(qū)別詳解_相關(guān)技巧
- 2022-10-16 Qt實現(xiàn)串口助手_C 語言
- 2022-05-12 HarmonyOS 單擊 雙擊 長按 滑動事件
- 2022-05-03 Docker?Desktop啟動失敗的解決(Docker?failed?to?initialize?
- 2022-10-27 golang?map的基本操作及定義方式_Golang
- 欄目分類
-
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支