簡介
Spring事物利用的是AOP,動態代理采用CGLIB代理(默認,也可以用Proxy代理,但是Proxy代理效率低於CGLIB代理)。故只要弄懂Spring的AOP實現,就知道為什么service本類中方法互相調用會導致事物失效。
失效案例
service層代碼
public void moneyTestOne(){
//1.查詢病人基本信息
List<TBICXX> tbicxx = basisDao.getTBICXX();
//2.根據CMZH更新TBMZFYHZ
Integer TBMZFYHZCount = tbmzfyhzDao.updateByCMZH("王五", "1903003643");
log.info("更新TBMZFYHZ影響行數{}",TBMZFYHZCount);
this.moneyTestTwo();
}
@Transactional(rollbackFor = Exception.class,propagation=Propagation.REQUIRED)
public void moneyTestTwo(){
//3.根據CMZH更新TBMZFYMXGH
Integer integer = tbmzfymxghDao.updateByCMZH("王五", "2107000224");
log.info("更新TBMZFYMXGH影響行數{}",integer);
int i=2/0;
}
Test層代碼
/**
* 測試其AOP事物(CGLIB代理):
* 如moneyTestOne不添加事物,則moneyTestTwo事物及其一切傳播行為將失效,這是由於spring的AOP的Cglib代理造成
* 同理: moneyTestOne添加事物,moneyTestTwo事物及其一切傳播行為也將失效,moneyTestTwo運行在moneyTestOne事物中。
* $$EnhancerBySpringCGLIB$$2364c0b7 代理
**/
@Test
public void testTransationalPropagation(){
log.info("測試開始,代理類{}",springTransactionSqlserverServiceImpl.getClass());
springTransactionSqlserverServiceImpl.moneyTestOne();
}
運行前
運行后
結論
moneyTestTwo方法事物並不生效,要想事物生效,只需要在moneyTestOne方法上加上事物注解(此方法同理會導致moneyTestTwo方法傳播行為失效),
失效分析
Spring通過AopProxy接口,抽象了這兩種實現,實現了一致的AOP方式:
現在看來,這種抽象同樣帶了一個缺陷,那就是抹殺了Cglib能夠直接創建普通類的增強子類的能力。下圖顯示了Spring的AOP代理類的實際調用過程:
解決辦法
事物聲明避免在一個類中互相調用,即moneyTestOne和moneyTestTwo要么都使用事物,要么直接分成兩個類。