spring

spring 事务处理中,同一个类中:A方法(无事务)调B方法(

2018-10-17  本文已影响12人  java面试收割机
@Override
    public Integer A(TestZhu testZhu) throws Exception {
        testZhu.setName("A");;
        springTransactionMapper.insert(testZhu);
        System.out.println("dsd");
        this.add(testZhu);
        int i = 1/0;
        return 1;
    }

    @Transactional(propagation=Propagation.REQUIRED)
    @Override
    public Integer B(TestZhu testZhu) {
        testZhu.setName("B");
        return springTransactionMapper.add(testZhu);
    }

此时,调用A方法,B里的事务将不生效

这个问题,表面上是事务声明失效的问题,实质上很可能是Spring的AOP机制实现角度的问题。我想到很久以前研究Spring的AOP实现时发现的一个现象:对于以Cglib方式增强的AOP目标类,会创建两个对象,一个事Bean实例本身,一个是Cglib增强代理对象,而不仅仅是只有后者。我曾经疑惑过这一点,但当时没有再仔细探究下去。

我们知道,Spring的AOP实现方式有两种:1、Java代理方式;2、Cglib动态增强方式,这两种方式在Spring中是可以无缝自由切换的。Java代理方式的优点是不依赖第三方jar包,缺点是不能代理类,只能代理接口。

Spring通过AopProxy接口,抽象了这两种实现,实现了一致的AOP方式:

image.png

现在看来,这种抽象同样带了一个缺陷,那就是抹杀了Cglib能够直接创建普通类的增强子类的能力,Spring相当于把Cglib动态生成的子类,当普通的代理类了,这也是为什么会创建两个对象的原因。下图显示了Spring的AOP代理类的实际调用过程:

image.png

因此,从上面的分析可以看出,methodB没有被AopProxy通知到,导致最终结果是:被Spring的AOP增强的类,在同一个类的内部方法调用时,其被调用方法上的增强通知将不起作用。

而这种结果,会造成什么影响呢:

  1:内部调用时,被调用方法的事务声明将不起作用

  2:换句话说,你在某个方法上声明它需要事务的时候,如果这个类还有其他开发者,你将不能保证这个方法真的会在事务环境中

  3:再换句话说,Spring的事务传播策略在内部方法调用时将不起作用。不管你希望某个方法需要单独事务,是RequiresNew,还是要嵌套事务,要Nested,等等,统统不起作用。

  4:不仅仅是事务通知,所有你自己利用Spring实现的AOP通知,都会受到同样限制。。。。

解决办法:

可以把方法B放到另外一个service或者dao,然后把这个server或者dao通过@Autowired注入到方法A的bean里面,这样即使方法A没用事务,方法B也可以执行自己的事务了。

原文出处:https://blog.csdn.net/qq_16675313/article/details/79955136

上一篇下一篇

猜你喜欢

热点阅读