【Bug】Spring在一个事物中开启新事物未生效
先看个缩减版的业务逻辑
逻辑上要求:当生成业务数据失败时,已落地的数据不可回滚
开发时将 数据落地 和 生成业务数据 这两个处理逻辑放在不同的事物中
@Service("asyncSendMessage")
public class AsyncSendMessageServiceImpl implements SendMessageService{
public Response doAsyncSendMessage(Request<Message> request){
// do something
this.indepHandleData(messageBO);
return reponse;
}
public void indepHandleData(MessageBO messageBO){
// handle data
}
}
<aop:aspectj-autoproxy proxy-target-class="true" />
<tx:advice id="advice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="do*" prapagation="REQUIRED" read-only="false" />
<tx:method name="indep*" propagation="REQUIRES_NEW" read-only="false" />
</tx:attributes>
</tx:advice>
启动项目发现,indepHandleData()
和 doAsyncSendMessage()
是在同一个事物中 ( indepHandleData()中抛出异常导致doAsyncSendMessage()中的数据会滚了 )
Spring 的事物实现是通过代理类来实现的,也就是我们调用doAsyncSendMessage()
时调用的是代理中的方法,而此时在doAsyncSendMessage
内部调用indepHandleData()
,则调用的是目标类中的方法,所以无法开启新事物。
为了在调用indepHandleData()
时开启新事物,需要调用代理类中的方法而不是目标类中的方法,解决方案有两种:
- 重新从Spring容器中获取当前对象
SendMessageService asyncSendMessage = (SendMessageService)SpringUtils.getBean("asyncSendMessage");
asyncSendMessage.indepHandleData(messageBO);
- 获取当前代理类对象
<!-- 添加expose-proxy=“true” 暴露当前代理对象 -->
<aop:aspectj-autoproxy proxy-target-class="true" expose-proxy=“true”>
((SendMessageService)AopContext.currentProxy()).indepHandleData(messageBO)