• sping事务失效的几种场景


    一.数据库引擎不支持事务

    spring的事务需要底层数据库引擎的支持

    这里以 MySQL 为例,其 MyISAM 引擎是不支持事务操作的,InnoDB 才是支持事务的引擎,一般要支持事务都会使用 InnoDB。

    根据 MySQL 的官方文档:

    http://dev.mysql.com/doc/refman/5.6/en/storage-engines.html

    从 MySQL 5.5.5 开始的默认存储引擎是:InnoDB,之前默认的都是:MyISAM,所以这点要值得注意,底层引擎不支持事务再怎么搞都是白搭。

    MySQL的几种引擎可以了解 https://www.cnblogs.com/zluckiy/p/13793799.html

    二.在非public修饰的方法使用

    以下来自 Spring 官方文档:

    When using proxies, you should apply the @Transactional annotation only to methods with public visibility. If you do annotate protected, private or package-visible methods with the @Transactional annotation, no error is raised, but the annotated method does not exhibit the configured transactional settings. Consider the use of AspectJ (see below) if you need to annotate non-public methods.

    大概意思就是 @Transactional 只能用于 public 的方法上,否则事务不会失效,如果要用在非 public 方法上,可以开启 AspectJ 代理模式。

    代码中解释:

    @Transactional注解使用的是AOP,在使用动态代理的时候只能针对public方法进行代理,源码依据在AbstractFallbackTransactionAttributeSource类中的computeTransactionAttribute方法中,如下:

    1 protected TransactionAttribute computeTransactionAttribute(Method method,
    2     Class<?> targetClass) {
    3         // Don't allow no-public methods as required.
    4         if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
    5         return null;
    6 }

    此处如果不是标注在public修饰的方法上并不会抛出异常,但是会导致事务失效。

    三.在try.catch代码段中,没有将异常抛出,导致事务无法回滚

    1 @Transactional
    2 public void method(){
    3   try{//错误不会回滚
    4     //插入一条数据
    5     //更改一条数据
    6   }catch(Exception ex){
    7     return;
    8   }
    9 }

    四.抛出的异常类型不对,默认为运行时异常RuntimeException

    1 @Transactional
    2 public void method(){
    3   try{
    4     //插入一条数据
    5     //更改一条数据
    6   }catch(Exception ex){
    7     return;
    8   }
    9 }

    这样事务也是不生效的,因为默认回滚的是:RuntimeException,如果你想触发其他异常的回滚,需要在注解上配置一下,如:

     1 @Transactional(rollbackFor = Exception.class)                                                                                                                             

    五.方法中调用同类的方法

     1 public class Test{
     2   public void A(){
     3     //插入一条数据
     4     //调用B方法
     5     B();
     6   }
     7   
     8   @Transactional
     9   public void B(){
    10     //插入数据
    11   }
    12 }

    简单的说就是一个类中的A方法(未标注声明式事务)在内部调用了B方法(标注了声明式事务),这样会导致B方法中的事务失效。

    为什么会失效呢?:其实原因很简单,Spring在扫描Bean的时候会自动为标注了@Transactional注解的类生成一个代理类(proxy),当有注解的方法被调用的时候,实际上是代理类调用的,代理类在调用之前会开启事务,执行事务的操作,但是同类中的方法互相调用,相当于this.B(),此时的B方法并非是代理类调用,而是直接通过原有的Bean直接调用,所以注解会失效。

    六.配置错误导致事务失效

    1.Propagation传播行为配置错误

    spring默认的事务传播属性是Propagation.REQUIRED,但是一旦配置了错误的传播属性,也是会导致事务失效,如下三种配置将会导致事务失效:

    Propagation.SUPPORTS

    Propagation.NOT_SUPPORTED

    Propagation.NEVER

    2代码中我们一般通过spring管理,去实现事务,需要注意代码块有没有被spring进行管理

    3数据源没有配置事务管理器等配置相关的问题导致

    参考https://javastack.blog.csdn.net/article/details/103871083

      https://blog.csdn.net/qq_34162294/article/details/105803966

  • 相关阅读:
    MongoDB安装与启动
    Mac node.js express-generator脚手架安装
    AJAX状态值与状态码
    博客园 Markdown编辑器简要教程
    高效、可维护、组件化的CSS
    如何在mac上运行vue项目
    前端chrome调试
    Light of future-冲刺集合
    团队作业第六次—事后诸葛亮
    Light of future-冲刺总结
  • 原文地址:https://www.cnblogs.com/zluckiy/p/13882229.html
Copyright © 2020-2023  润新知