Spring事務失效的一種原因關於this調用的問題

  • PROPAGATION_REQUIRED: 如果存在一個事務,則支持當前事務。如果沒有事務則開啟事務;
  • PROPAGATION_REQUIRES_NEW:總是開啟一個新的事務。如果一個事務已經存在,則將這個存在的事務掛起;

問題:

Spring中一個沒有事務的方法A調用一個默認事務(PROPAGATION_REQUIRED)的方法B時,如果使用this調用方法B,方法B拋出RuntimeException,此時方法B事務未生效,不會回滾。

@Service
public class EmployeeService {
 
    @Autowired
    private EmployeeDao employeeDao;
 
    public void save(){
        try {        
            this.saveEmployee();  //此處this調用不會開啟事務,數據會被保存
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    
    @Transactional(propagation = Propagation.PROPAGATION_REQUIRED)
    //此處無論是PROPAGATION_REQUIRED還是PROPAGATION_REQUIRES_NEW,事務均不生效
    public void saveEmployee(){
        Employee employee = new Employee();
        employee.setName("zhangsan");
        employee.setAge("26";
        employeeDao.save(employee);
        throw new RuntimeException();
    }
}

問題原因:

JDK的動態代理。隻有被動態代理直接調用時才會產生事務。在SpringIoC容器中返回的調用的對象是代理對象而不是真實的對象。而這裡的this是EmployeeService真實對象而不是代理對象。

解決辦法:

方法1、在方法A上開啟事務,方法B不用事務或默認事務,並在方法A的catch中throw new RuntimeException();(在沒指定rollbackFor時,默認回滾的異常為RuntimeException),這樣使用的就是方法A的事務。(一定要throw new RuntimeException();否則異常被捕捉處理,同樣不會回滾。)如下:

@Transactional() //開啟事務
public void save(){
    try {        
        this.saveEmployee();  //這裡this調用會使事務失效,數據會被保存
    }catch (Exception e){
        e.printStackTrace();
        throw new RuntimeException();
    }
}

方法2、方法A上可以不開啟事務,方法B上開啟事務,並在方法A中將this調用改成動態代理調用(AopContext.currentProxy()),如下:

public void save(){
    try {        
        EmployeeService proxy =(EmployeeService) AopContext.currentProxy();
        proxy.saveEmployee();
    }catch (Exception e){
        e.printStackTrace();
    }
}

到此這篇關於spring事務調用失效問題的文章就介紹到這瞭,更多相關spring事務調用失效問題內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: