日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學(xué)無先后,達(dá)者為師

網(wǎng)站首頁 編程語言 正文

Spring 事務(wù)失效的場景

作者:Mr.VK 更新時間: 2024-03-08 編程語言

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種:privatedefaultprotectedpublic,它們的權(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)建新事物:REQUIREDREQUIRES_NEWNESTED

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

  • 上一篇:沒有了
  • 下一篇:沒有了
欄目分類
最近更新