Spring 事务失效的底层原因探讨

@Transactional

@Transactianal(propagation=Propagation.REQUIRED)

-如果当前线程存在事务,则使用该事务,否则新建一个事务

@Transaction(propagation=Propagation.REQUIRES_NEW)

-如果当前线程存在事务,则挂起当前事务,然后开启一个新事务继续执行,新事务执行完毕之后,继续唤醒之前挂起的事务继续执行,如果当前线程不存在事务,则新建一个事务。

@Service
public class CityServiceImpl implements CityService {

    private final static Logger LOGGER = LoggerFactory.getLogger(CityServiceImpl.class);

    @Autowired
    private CityDao cityDao;

    /**
     * 解决方案2:
     *通过spring应用上下文 获取 代理对象
     * ApplicationContext 在ioc容器中是单例的
     */

    private CityServiceImpl proxy;
    @Autowired
    private ApplicationContext context;
    @PostConstruct
    public  void init(){
        proxy=context.getBean(CityServiceImpl.class);
    }


    /**
     *需求:
     * 1:parent()是核心方法,在执行Parent业务之前需要执行Child子业务
     * 2:child方法是一个不重要的业务方法,child方法无论是否抛出异常,对parent的执行都不能有影响
     *
     *
     * 使用try、catch 自己处理不去而抛出异常
     * 预测结果:
     * 1:child 失败
     * 2:parent 成功
     *实际结果:
     * 1:child 成功
     * 2:parent 成功
     *    这种情况child事务失效  【原因:动态代理】
     *
     *    事物的执行者:AopProxy  aop的代理类  通过AopProxy调用parent()方法
     *    spring的事务是基于AOP的 通过aop 的环绕增强在 源代码执行之后 对数据进行commit或rollback
     *
     * 这种情况child事务失效
     * 根据动态代理分析 此处的child()不是由 AopProxy调用的 而是 this对象
     *
     * 解决方案 此处的child方法需是动态代理对象调用的 事务才不会失效
     * funcation 1: 从当前线程的AopContext中获取
     * CityServiceImpl proxy=(CityServiceImpl)AopContext.currentProxy();
     * proxy.child()
     *
     * funcation 2: 通过spring应用上下文 获取 代理对象
     * ApplicationContext 在ioc容器中是单例的
     */
    @Override
    @Transactional
    public void parent() {
        LOGGER.info("======================insertParent()===================");

        //这种情况child事务失效
        //根据动态代理分析 此处的child()不是由 AopProxy调用的 而是 this对象
        try {
            //com.tengxvincent.transaction.SpringTransaction.service.impl.CityServiceImpl
            System.out.println("child invoked object :"+this.getClass().getName());
            //child();

            /**
             * 解决方案 此处的child方法需是动态代理对象调用的 事务才不会失效
             * funcation 1: 从当前线程的AopContext中获取
             */
            //CityServiceImpl proxy=(CityServiceImpl)AopContext.currentProxy();
            proxy.child();

        }catch (Exception e){
            LOGGER.error("parent catch child execption ",e);
        }

        //以下代码为Parent业务
        City city= new City();
        city.setProvinceId(Long.valueOf(99));
        city.setCityName("parent");
        city.setDescription("parentparentparentparent");
        cityDao.insertCity(city);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void child() {
        LOGGER.info("======================insertChild()===================");
        City city= new City();
        city.setProvinceId(Long.valueOf(99));
        city.setCityName("Child");
        city.setDescription("ChildChildChildChildChildChild");
        cityDao.insertCity(city);
        int a=1/0;//此处异常
    }

}

注意  1 在spring ioc容器中 如果不特殊处理 默认情况 所有的对象都是代理对象

        2 ApplicationContext 是单例的


源码下载:    https://github.com/tengxvincent/Spring_Transaction.git


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值