一、业务需求:一个循环,循环中会调用数据库,而且还有业务处理逻辑,现在要求循环中的异常不能中断循环的执行
二、解决:可以将循环体中的内容单独提出写成一个方法,并在上面加上@Transactional(rollbackFor = Exception.class)
这种解决有问题,经过测试,此时的事务是不起作用的,数据依然会被插入(或修改)
三、进一步解决:spring中的事务管理使用到了代理模式,方法直接调用内部方法是不会走到代理类的,也就是不会走到切面,所以@Transactional可能会失效,所以直接调用相当于this.调用内层方法时是不生效的,因此要通过代理对象的方式调用内层方法,
获取代理对象的方法:
Object proxy = AopContext.currentProxy();
//使用时强转为方法所在类
ServiceImpl proxy = (ServiceImpl)AopContext.currentProxy(); Serviceimpl为方法所在类
注意:
要在方法所在类(也就是要获取的代理对象的类上加上下面注解),否则会出现异常信息:
Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available.
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
也可以通过配置xml
<aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>
这样就可以使事务生效,如果外层的方法也要加上事务,需要在内层的事务上加上propagation=Propagation.NESTED属性,让内层事务不会影响到外层事务。
~~~~~~~~~~~~~~~~~~~~~~~~~~以下为测试代码~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Service
@EnableAspectJAutoProxy(proxyTargetClass = true,exposeProxy = true)//注意项
public class HistoryStockServiceImpl extends BaseService implements HistoryStockService {
...
@Override
public void test() {
HistoryStockServiceImpl service = (HistoryStockServiceImpl)AopContext.currentProxy();
for (int i = 0; i < 10; i++) {
try {
service.upda(i);
System.out.println("~~~~~~~~~~~i:"+i);
} catch (Exception e) {
System.out.println(e.getMessage());
}
System.out.println("~~~~~~~~~~~~~~循环次数:"+i);
}
System.out.println("~~~~~~~~~~~~~运行结束");
}
@Transactional(propagation = Propagation.NESTED,rollbackFor = Exception.class)
public void upda(int a){
historyStockMapper.upda();
if(a==5){
int i=1/0;
}
}
dao层为普通的修改数据库加1操作,此处不粘图
结果:除第5此异常外,其他日志正常数据,数据库由0增加到了9
方法2:可以将循环内层的需要事务的方法写到其他的处理类中,在此类中引入那个类也可以使事务生效
百度参考:https://www.cnblogs.com/qsbnj/p/14389703.html和https://www.cnblogs.com/yanggb/p/13227072.html