• @Transactional注解失效的解决方案


    一、前言

      开发中我们经常使用 @Transactional注解来启用Spring事务管理,但是如果使用方法不当,会遇到注解不生效该事务回滚的地方却没有回滚的问题。
    总结下一般是以下几个原因:

    1. @Transactional 注解只能应用到 public 可见度的方法上。 如果应用在protected、private或者 package可见度的方法上,也不会报错,不过事务设置不会起作用。
    2. 默认情况下,spring会对unchecked异常进行事务回滚;如果是checked异常则不回滚。针对这种情况,可以try catch checked异常后进行手动事务回滚。
    3. 数据库引擎要支持事务,如果是mysql,注意表要使用支持事务的引擎,比如InnoDB,如果是MyISAM,事务是不起作用的。
    4. 同一个类中, 一个no-transactional的方法去调用transactional的方法, 事务会失效。

    本文主要讲第四种情况如何处理。

    二、示例

     

    事务失效示例1
    事务失效示例1

     

     

    事务失效示例2
    事务失效示例2

     

    执行add() 方法后数据库插入了两条数据,也就说明以上两段代码中,doAdd()方法的事务增强都不会执行,具体原因可以参考这篇文章

    那么如果想让doAdd()方法在发生异常时数据库事务回滚,有什么解决办法吗?

    第一步开启配置expose-proxy

    如果使用的xml配置文件的方式,则添加如下内容:

    <aop:aspectj-autoproxy  expose-proxy="true"  />
    

    如果用的SpringBoot框架,则直接在启动类上添加如下注解即可。

    @EnableAspectJAutoProxy(proxyTargetClass = true,exposeProxy = true)
    

    第二步修改代码
    将原来的调用代码this.doAdd(person); 改为 ((PersonService)AopContext.currentProxy()).doAdd(person);

     

    enter description here
    enter description here

     

    再进行测试发现数据库只插入了一条数据(person2),说明doAdd() 方法里的事务增强生效了。

    三、源码分析

    点进 @EnableAspectJAutoProxy 注解代码如下:

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import(AspectJAutoProxyRegistrar.class)
    public @interface EnableAspectJAutoProxy {
    
        boolean proxyTargetClass() default false;
    
        boolean exposeProxy() default false;
    
    }
    

    发现它注入了一个Bean AspectJAutoProxyRegistrar,再看看这个AspectJAutoProxyRegistrar是什么。

    class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
    
        public void registerBeanDefinitions(
                AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    
            AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
            // 解析注解EnableAspectJAutoProxy
            AnnotationAttributes enableAspectJAutoProxy =
                    AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
            if (enableAspectJAutoProxy != null) {
                if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
                    AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
                }
                if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
                    // 如果设置了exposeProxy=true就强制使用
                    AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
                }
            }
        }
    
    }
    

    AopConfigUtils#forceAutoProxyCreatorToExposeProxy

    // 强制使用的过程其实也是一个属性设置的过程
        public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
            if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
                BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
                definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
            }
        }
        
        /**
         * The bean name of the internally managed auto-proxy creator.
         */
        public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
                "org.springframework.aop.config.internalAutoProxyCreator";
    
  • 相关阅读:
    【bzoj3782】上学路线 dp+容斥原理+Lucas定理+中国剩余定理
    【bzoj3210】花神的浇花集会 旋转坐标系
    【bzoj3513】[MUTC2013]idiots FFT
    【bzoj1043】[HAOI2008]下落的圆盘 计算几何
    【bzoj2521】[Shoi2010]最小生成树 网络流最小割
    【bzoj4811】[Ynoi2017]由乃的OJ 树链剖分+线段树区间合并
    【bzoj2467】[中山市选2010]生成树 矩阵树定理
    【bzoj1002】[FJOI2007]轮状病毒 矩阵树定理+高精度
    【bzoj4031】[HEOI2015]小Z的房间 矩阵树定理
    【bzoj4292】[PA2015]Równanie 暴力
  • 原文地址:https://www.cnblogs.com/2YSP/p/11748389.html
Copyright © 2020-2023  润新知