spring 事物回滚失败

在spring 中进行事物管理的时候,N种情况会出现事物回滚失败

1)在事物中调用自己的其他的方法,但是进行捕获了异常。

@Transtaion

public void save(){

        try{

save2()

}catch{

}

mapper.insert()

}

@Transatinal(开启新的事物)

public  void save2(){

mapper.insert()

1/0

}

这里的调用会出现回滚失败的问题。我们本来想要实现的功能是,第一个插入失败了,因为出现了异常。需要进行回滚

但是没有回滚,这一次两个记录都会插入成功。

这是因为Spring中的事物是通过Aop来实现的,代理类在进行调用save 方法的时候是通过代理调用的,此时会开启事物,但是这里如果是调用自身方法的时候,就是没有通过代理对象来调用,而是通过ServerImpl自身的方法,此时是没有开启事物的。因此不会进行回滚。

这里如果想要做到回滚的话,可以通过拿到我们的代理类来进行调用。

获取代理类的方法有多种,

1)

通过ThreadLocal暴露Aop代理对象

1、开启暴露Aop代理到ThreadLocal支持(如下配置方式从spring3开始支持)

Java代码  
  1. <aop:aspectj-autoproxy expose-proxy="true"/><!—注解风格支持-->  
Java代码  
  1. <aop:config expose-proxy="true"><!—xml风格支持-->   

2)ApplicationContext

一、定义BeanPostProcessor 需要使用的标识接口

Java代码  
  1. public interface BeanSelfAware {  
  2.     void setSelf(Object proxyBean);  
  3. }  

 即我们自定义的BeanPostProcessor (InjectBeanSelfProcessor)如果发现我们的Bean是实现了该标识接口就调用setSelf注入代理对象。

 

二、Bean实现

Java代码  
  1. @Service  
  2. public class AServiceImpl4 implements AService, BeanSelfAware {//此处省略接口定义  
  3.     private AService proxySelf;  
  4.     public void setSelf(Object proxyBean) { //通过InjectBeanSelfProcessor注入自己(目标对象)的AOP代理对象  
  5.         this.proxySelf = (AService) proxyBean;  
  6.     }  
  7.     @Transactional(propagation = Propagation.REQUIRED)  
  8.     public void a() {  
  9.         proxySelf.b();//调用代理对象的方法 这样可以执行事务切面  
  10.     }  
  11.     @Transactional(propagation = Propagation.REQUIRES_NEW)  
  12.     public void b() {  
  13.     }  
  14. }   

改进版的InjectBeanSelfProcessor的解决方案


Java代码  
  1. @Component  
  2. public class InjectBeanSelfProcessor2 implements BeanPostProcessor, ApplicationContextAware {  
  3.     private ApplicationContext context;  
  4.     //① 注入ApplicationContext  
  5.     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {  
  6.         this.context = applicationContext;  
  7.     }  
  8.     public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {  
  9.         if(!(bean instanceof BeanSelfAware)) { //② 如果Bean没有实现BeanSelfAware标识接口 跳过  
  10.             return bean;  
  11.         }  
  12.         if(AopUtils.isAopProxy(bean)) { //③ 如果当前对象是AOP代理对象,直接注入  
  13.             ((BeanSelfAware) bean).setSelf(bean);  
  14.         } else {  
  15.             //④ 如果当前对象不是AOP代理,则通过context.getBean(beanName)获取代理对象并注入  
  16.             //此种方式不适合解决prototype Bean的代理对象注入  
  17.             ((BeanSelfAware)bean).setSelf(context.getBean(beanName));  
  18.         }  
  19.         return bean;  
  20.     }  
  21.     public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {  
  22.         return bean;  
  23.     }  
  24. }  

3)

通过初始化方法在目标对象中注入代理对象

Java代码  
  1. @Service  
  2. public class AServiceImpl3 implements AService{  
  3.     @Autowired  //①  注入上下文  
  4.     private ApplicationContext context;  
  5.       
  6.     private AService proxySelf; //②  表示代理对象,不是目标对象  
  7.     @PostConstruct  //③ 初始化方法  
  8.     private void setSelf() {  
  9.         //从上下文获取代理对象(如果通过proxtSelf=this是不对的,this是目标对象)  
  10.         //此种方法不适合于prototype Bean,因为每次getBean返回一个新的Bean  
  11.         proxySelf = context.getBean(AService.class);   
  12.     }  
  13.     @Transactional(propagation = Propagation.REQUIRED)  
  14.     public void a() {  
  15.        proxySelf.b(); //④ 调用代理对象的方法 这样可以执行事务切面  
  16.     }  
  17.     @Transactional(propagation = Propagation.REQUIRES_NEW)  
  18.     public void b() {  
  19.     }  
  20. }  

@Transtaion

public void save(){

        try{

(Service(AopContext.currentProxy())).save2()

}catch{

}

mapper.insert()

}

解决办法2:  如下或抛出RuntimeException
  1. if(userSave){          
  2.     try {          
  3.         userDao.save(user);          
  4.         userCapabilityQuotaDao.save(capabilityQuota);          
  5.     } catch (Exception e) {          
  6.         logger.info("能力开通接口,开户异常,异常信息:"+e);          
  7.         TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();         
  8.     }         
  9.  }  

2)AOP配置文件没有正确配置的

3)Controller package  和service package 要精确配置到对应的包



参考:https://www.cnblogs.com/tianyuchen/p/6678084.html

         https://www.cnblogs.com/hanxue53/p/5280099.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值