在做業務開發時,遇到了一個事務不起作用的問題。大概流程是這樣的,方法內部的定時任務調用了一個帶事務的方法,失敗后事務沒有回滾。查閱資料后,問題得到解決,記錄下來分享給大家。
場景
我在這里模擬一個場景,大概的調用方式就如下面的代碼這樣。
@Override
@Transactional(rollbackFor = RuntimeException.class)
public void insertUser(User user) {
userMapper.insertUser(user);
throw new RuntimeException("");
}
/**
* 內部調用新增方法
*
* @param user
*/
@Override
public void invokeInsertUser(User user) {
this.insertUser(user);
}
原因
AOP
使用的是動態代理的機制,它會給類生成一個代理類,事務的相關操作都在代理類上完成。內部方式使用this
調用方式時,使用的是實例調用,並沒有通過代理類調用方法,所以會導致事務失效。
解決辦法
方法一 引入自身bean
在類內部通過@Autowired
將本身bean
引入,然后通過調用自身bean
,從而實現使用AOP
代理操作。
注入自身bean
@Autowired
@Lazy
private UserService service;
修改invokeInsertUser
方法
/**
* 解決方法一 在bean中將自己注入進來
* @param user
*/
@Override
public void invokeInsertUser(User user) {
this.service.insertUser(user);
}
方法二 通過ApplicationContext引入bean
通過ApplicationContext
獲取bean
,通過bean
調用內部方法,就使用了bean
的代理類。
注入ApplicationContext
@Autowired
ApplicationContext applicationContext;
修改invokeInsertUser
方法
/**
* 解決方法二 通過applicationContext獲取到bean
* @param user
*/
@Override
public void invokeInsertUser(User user) {
((UserService)applicationContext.getBean("userService")).invokeInsertUser(user);
}
方法三 通過AopContext獲取當前類的代理類
通過AopContext
獲取當前類的代理類,直接通過代理類調用方法
在引導類上添加@EnableAspectJAutoProxy(exposeProxy=true)
注解
修改invokeInsertUser
方法
/**
* 解決方法三 通過applicationContext獲取到bean
*
* @param user
*/
@Override
public void invokeInsertUser(User user) {
((UserService) AopContext.currentProxy()).invokeInsertUser(user);
}
以上就是內部方法調用時,事務不起作用的原因及解決辦法。
最后
打個小廣告,金九銀十跳槽季,平頭哥給大家整理了一份較全面的 Java 學習資料,歡迎掃碼關注微信公眾號:「平頭哥的技術博文」領取,祝各位升職加薪。