今天在項(xiàng)目想測(cè)試一下事務(wù)回滾是否生效,還好心血來潮祷舀,突然發(fā)現(xiàn)數(shù)據(jù)無(wú)法回滾,問題很嚴(yán)重啊C镳小夺克!!
這是我的測(cè)試代碼
@Override
@Transactional(rollbackFor = Exception.class)
public void update(MerchantUpdateDTO condition) throws CustomException {
// 查詢待更新的商戶
Merchant updateMerchant = merchantMapper.selectById(condition.getId());
if (updateMerchant == null) {
throw new CustomException("編輯的商戶不存在");
}
// 更新商戶信息
BeanUtils.copyProperties(condition, updateMerchant);
updateMerchant.setAccountStatus(AccountStatus.PENDING_REVIEW);
merchantMapper.updateById(updateMerchant);
throw new CustomException("編輯的商戶不存在");
}
一開始我懷疑是網(wǎng)上常見的幾種
1、檢查數(shù)據(jù)庫(kù)的引擎是否是innoDB
2嚎朽、啟動(dòng)類上是否加入@EnableTransactionManagement注解
3铺纽、是否在方法上加入@Transactional注解或Service的類上是否有@Transactional注解
4、方法是否為public
5哟忍、是否是因?yàn)閽伋隽薊xception等checked異常
檢查過后我發(fā)現(xiàn)都沒問題的狡门,這時(shí)候我就嘗試放到新建的類中測(cè)試,發(fā)現(xiàn)居然可以了锅很。
為啥舊的類不行呢其馏,有啥區(qū)別呢
我這邊檢查到舊的類是注入到shiro Realm的
接著我去網(wǎng)上了解相關(guān)信息
錯(cuò)誤原因:
Spring中事務(wù)是通過AOP創(chuàng)建代理對(duì)象來完成的,有BeanFactoryTransactionAttributeSourceAdvisor完成對(duì)需要事務(wù)的方法織入對(duì)事務(wù)的處理爆安。完成創(chuàng)建AOP代理對(duì)象的功能由一個(gè)特殊的BeanPostProcessor完成--AnnotationAwareAspectJAutoProxyCreator叛复。該類實(shí)現(xiàn)了BeanPostProcessor接口,在bean創(chuàng)建完成并將屬性設(shè)置好之后扔仓,攔截bean褐奥,并創(chuàng)建代理對(duì)象,在原對(duì)象的方法功能上添加增強(qiáng)器中增強(qiáng)方法的處理翘簇。對(duì)于事務(wù)增強(qiáng)器BeanFactoryTransactionAttributeSourceAdvisor而言撬码,也就是在原有方法上加入事務(wù)的功能。
但是版保,在ApplicationContext刷新上下文過程(refresh)中呜笑,上下文會(huì)調(diào)用registerBeanPostProcessors方法將BeanFactory中的所有BeanPostProcessor后處理器注冊(cè)到BeanFactory中,使其后面流程中創(chuàng)建bean的時(shí)候生效
由于ShiroFilterFactoryBean實(shí)現(xiàn)了FactoryBean接口彻犁,所以它會(huì)提前被初始化叫胁。又因?yàn)镾ecurityManager,SecurityManager依賴于Realm實(shí)現(xiàn)類汞幢、Realm實(shí)現(xiàn)類又依賴于MerchantService驼鹅,所以引發(fā)所有相關(guān)的bean提前初始化。
ShiroFilterFactoryBean -> SecurityManager -> Realm實(shí)現(xiàn)類 -> MerchantService
但是此時(shí)還只是ApplicationContext中registerBeanPostProcessors注冊(cè)BeanPostProcessor處理器的階段急鳄,此時(shí)AnnotationAwareAspectJAutoProxyCreator還沒有注冊(cè)到BeanFactory中谤民,MerchantService無(wú)法享受到事務(wù)處理!
解決辦法:
1疾宏、在Realm實(shí)現(xiàn)中使用Mapper张足,而不是直接使用Service對(duì)象。缺點(diǎn):直接和數(shù)據(jù)庫(kù)交互坎藐,并且也沒有Service中的邏輯交互以及緩存
2为牍、在Realm中Service聲明上加入@Lazy注解哼绑,延遲Realm實(shí)現(xiàn)中Service對(duì)象的初始化時(shí)間,這樣就可以保證Service實(shí)際初始化的時(shí)候會(huì)被BeanPostProcessor攔截碉咆,創(chuàng)建具有事務(wù)功能的代理對(duì)象