• Spring事务失效的八种场景


    1、方法内的自调用Spring事务是基于AOP的,只有使用代理对象调用某个方法时,Spring事务才能生效,而在一个方法中使用this.xxx()调用方法时,this并不是代理对象,所以会导致事务失效。

            1)解放方案1:把调用方法拆分到另外一个Bean中;

            2)解决方案2:自己注入自己,通过Spring生成自己的代理对象,来调其它方法;

            3)解决方案3:开启@EnableAspectAutoProxy(exposeProxy = true),通过AopContext.currentProxy()获取代理对象。

    2、方法是private的:Spring事务会基于CGLIB来进行AOP,而CGLIB会基于父子类来实现的,子类是代理类,父类是被代理类,如果父类中的某个方法是private的,那么子类就没有办法重写它,也就没有办法额外增加Spring事务的逻辑。

    3、方法是final的:原因和private是一样的,也是由于子类不能重写父类中的final的方法。

    4、单独的线程调用方法:当Mybatis或JdbcTemplate执行SQL时,会从ThreadLocal中去获取数据库连接对象,如果开启事务的线程和执行SQL的线程是同一个,那么就能拿到数据库连接对象,如果不是同一个,那就拿不到数据库连接对象,这样,Mybatis或JdbcTemplate就会自己新建一个数据库连接用来执行SQL,此数据库连接的autocommit为true,那么执行完SQL就会提交,后续再抛异常也就不能再回滚之前已经提交了的SQL了。

    5、没加@Configuration注解:如果用SpringBoot基本没有这个问题,但是如果用的Spring,那么可能会有这个问题,这个问题的原因其实也是由于Mybatis或JdbcTemplate会从ThreadLocal中去获取数据库连接,但是ThreadLocal中存储的是一个Map,Map的key为DataSource对象,value为连接对象,而如果我们没有在AppConfig上添加@Configuration注解的话,会导致Map中存的DataSource对象与MyBatis或者JdbcTemplate中的DataSource对象不相等,从而也拿不到数据库连接,导致自己去创建数据库连接了。

    6、异常被吃掉:如果Spring事务没有捕获到异常,那么也就不会回滚了,默认情况Spring会捕获RuntimeException和Error。

    7、类没有被Spring管理:没有交给Spring进行管理,就不会生成代理对象,更别说执行事务了。

    8、数据库不支持事务:Spring的事务管理是建立在数据库事务之上的,所以他不仅要保证sql语句的原子性,还要保证自己方法的原子性,数据库都不支持事务了,事务当然会失效啦。

    ps:以下是我整理的java面试资料,密码是obht,感兴趣的可以看看。最后,创作不易,觉得写得不错的可以点点关注!

    链接:https://www.yuque.com/u39298356/uu4hxh?# 《Java面试宝典》 

  • 相关阅读:
    Unity Android(九)USB权限弹窗问题
    包管理工具详解npm、yarn、cnpm、npx、pnpm
    图论 - 拓扑排序
    常用排序算法详解
    Qt读写ini
    C语言:生成校验码
    Flutter 绘制美不胜收的光影流动效果
    抖音短视频矩阵系统多账号矩阵源头开发源码分享
    网络通信与网络协议
    【Vue】【uni-app】工单管理页面实现
  • 原文地址:https://blog.csdn.net/qq_53281187/article/details/136521053