@Transactional失效

一、场景一
1、下单成功后发送短信通知

@Override
@Transactional
public void travel() throws Exception {
    order();
    try {
        sendMail();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

@Override
 //@Async
 @Transactional
 public void sendMail() throws Exception {
     TransactionalTest test = new TransactionalTest();
     test.setOrderId(System.currentTimeMillis());
     test.setName("sendMail");
     transactionalTestMapper.insertMail(test);
     if(true){
         throw new Exception("");
     }
 }

本意:
订单成功:订单表有数据;短信失败:短信表数据回滚

实际:
订单成功:订单表有数据;短信失败:短信表数据有数据没有回流
事物注解失效了。
原因:
spring aop注解是通过动态代理实现的,调用travel,时 spring aop会建立一个动态代理对象调用travel(), 在travel前后会添加事物增强的方法. 而在travel方法内部调用sendMail 是通过this 调用的没有用代理对象 ,所以sendMail的事物不生效,那么我们只要在调用sendMail前 拿到当前travel方法的动态代理对象 ,用这个动态代理对象调用sendMail就可以解决这个问题, 需要在启动类加上注解@EnableAspectJAutoProxy(exposeProxy = true,proxyTargetClass=true).并改进service后方法如下:

@Override
@Transactional
public void travel() throws Exception {
    System.out.println("=======================");
    System.out.println(Thread.currentThread().getName());
    order();
    //hotel();
    try {
        TransactionalTestServiceImpl currentProxy = (TransactionalTestServiceImpl)AopContext.currentProxy();
        System.out.println("======================="+currentProxy);
        currentProxy.sendMail();
    } catch (Exception e) {
        e.printStackTrace();
    }
 

}
@Override
@Transactional
public void sendMail() throws Exception {
    System.out.println("=======================");
    System.out.println(Thread.currentThread().getName());
    TransactionalTest test = new TransactionalTest();
    test.setOrderId(System.currentTimeMillis());
    test.setName("sendMail");
    transactionalTestMapper.insertMail(test);
    if(true){
        throw new Exception("");
    }
}

理想:订单表成功,短信表回滚
实际:订单表成功,短信表成功
为什么? 明明已经用动态代码对象调用的sendMail方法.
原因: 因为我们抛出的是Exception 异常.
Spring的AOP即声明式事务管理默认是针对unchecked exception回滚。也就是默认对RuntimeException()异常或是其子类进行事务回滚;checked异常,即Exception可try{}捕获的不会回滚,如果使用try-catch捕获抛出的unchecked异常后没有在catch块中采用页面硬编码的方式使用spring api对事务做显式的回滚,则事务不会回滚.
有2种解决方法,
一 就是我们自定义一个SysServiceException异常类, 把抛出的异常换成SysServiceException.

@Override
@Transactional
public void sendMail() throws Exception {
    System.out.println("=======================");
    System.out.println(Thread.currentThread().getName());
    TransactionalTest test = new TransactionalTest();
    test.setOrderId(System.currentTimeMillis());
    test.setName("sendMail");
    transactionalTestMapper.insertMail(test);
    if(true){
        throw new SysServiceException("");
    }
}

二 在@Transactional加上@Transactional(rollbackFor = Exception.class)
显然加上(rollbackFor = Exception.class)会更好.
其它:包括我们遇到到@Async 注解,时也用获取当前代理对象解决,不生效问题

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值