@Transactional 注解哪些情况下会失效?[java教程]

@Transactional 注解哪些情况下会失效?

@Transactional 注解哪些情况下会失效?[java教程]

今天又研究了一道面试题,有关 @Transactional 注解失效的问题,这道题的综合性较强。

先说下我整理的答案:

1、@Transactional 作用在非 public 修饰的方法上

2、@Transactional 作用于接口,使用 CGLib 动态代理

3、@Transactional 注解属性 propagation 设置以下三种可能导致无法回滚

  • SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
  • NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
  • NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。

4、同一类中加 @Transactional 方法被无 @Transactional 的方法调用,事务失效

5、@Transactional 方法内异常被捕获

6、默认 RuntimeException 和 Error 及子类抛出,会回滚;rollbackFor 指定的异常及子类发生才会回滚

7、数据库不支持事务,如 MySLQL 使用 MyISAM 存储引擎

8、Spring 的配置文件中未配置事务注解生效

<tx:annotation-driven transaction-manager="transactionManager"/>

9、Spring Boot 引入 jbdc 或 jpa 包,默认开启事务注解。若未引入这两个包,需要使用 @EnableTransactionManagement 进行配置

简单分析一下:

@Transactional 注解的作用就是保证方法内的多个数据库操作具有事务特性,即要么都成功,要么都失败。

失效的本质原因就在注解启用、事务管理器注入、手动 commit 与 rollback 的处理(Connection 的 autoCommit 设置为 false,然后在代码里手动 commit 或 rollback)这三个环节中。

比如我的博客网站 xml 配置文件中配置的事务管理器就是

org.springframework.jdbc.datasource.DataSourceTransactionManager

它继承自

org.springframework.transaction.support.AbstractPlatformTransactionManager

事务的具体控制就是 DataSourceTransactionManager 实现。

 

Spring 启动时解析 xml 配置,把 TransactionInterceptor 类型的 bean 注入到了 BeanFactoryTransactionAttributeSourceAdvisor 中,调用 TransactionInterceptor 的 invoke 方法完成整个事务的逻辑。

@Override
  public Object invoke(final MethodInvocation invocation) throws Throwable {
    // Work out the target class: may be {@code null}.
    // The TransactionAttributeSource should be passed the target class
    // as well as the method, which may be from an interface.
    Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);// Adapt to TransactionAspectSupport's invokeWithinTransaction...
    return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
      @Override
      public Object proceedWithInvocation() throws Throwable {
        return invocation.proceed();
      }
    });
  }

invokeWithinTransaction 方法就是对事务的处理。

@Transactional 仅作用于 public 方法的逻辑在 getTransactionAttribute 方法中

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

@Transactional 的注解参数解析逻辑在 invokeWithinTransaction 方法里

//If the transaction attribute is null, the method is non-transactional.
    final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
// First try is the method in the target class.
    TransactionAttribute txAtt = findTransactionAttribute(specificMethod);
    if (txAtt != null) {
      return txAtt;
    }// Second try is the transaction attribute on the target class.
    txAtt = findTransactionAttribute(specificMethod.getDeclaringClass());
    if (txAtt != null) {
      return txAtt;
    }if (specificMethod != method) {
      // Fallback is to look at the original method.
      txAtt = findTransactionAttribute(method);
      if (txAtt != null) {
        return txAtt;
      }
      // Last fallback is the class of the original method.
      return findTransactionAttribute(method.getDeclaringClass());
    }

事务信息通过 createTransactionIfNecessary 方法创建

// Standard transaction demarcation with getTransaction and commit/rollback calls.TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);

代码执行发生异常的处理逻辑是在 completeTransactionAfterThrowing 方法中

completeTransactionAfterThrowing(txInfo, ex);

根据注解参数 rollback

if (txInfo.transactionAttribute.rollbackOn(ex)) {
        try {
          txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
        }
        catch (TransactionSystemException ex2) {
          logger.error("Application exception overridden by rollback exception", ex);
          ex2.initApplicationException(ex);
          throw ex2;
        }
        catch (RuntimeException ex2) {
          logger.error("Application exception overridden by rollback exception", ex);
          throw ex2;
        }
        catch (Error err) {
          logger.error("Application exception overridden by rollback error", ex);
          throw err;
        }
      }

根据注解参数 commit

else {
        // We don't roll back on this exception.
        // Will still roll back if TransactionStatus.isRollbackOnly() is true.
        try {
          txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
        }
        catch (TransactionSystemException ex2) {
          logger.error("Application exception overridden by commit exception", ex);
          ex2.initApplicationException(ex);
          throw ex2;
        }
        catch (RuntimeException ex2) {
          logger.error("Application exception overridden by commit exception", ex);
          throw ex2;
        }
        catch (Error err) {
          logger.error("Application exception overridden by commit error", ex);
          throw err;
        }
      }
    }

代码执行正常的事务提交在 commitTransactionAfterReturning 方法

commitTransactionAfterReturning(txInfo);

以上就是 Spring 对事务的处理流程。

给TA打赏
共{{data.count}}人
人已打赏
Java

消息大量积压怎么解决?

2020-7-31 9:18:20

Java

Mysql 中 exists 和 in 的区别[java教程]

2020-7-31 11:08:52

本站所发布的一切源码、模板、应用等文章仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权。本站内容适用于DMCA政策。若您的权利被侵害,请与我们联系处理,站长 QQ: 84087680 或 点击右侧 私信:盾给网 反馈,我们将尽快处理。
⚠️
本站所发布的一切源码、模板、应用等文章仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权。本站内容适用于DMCA政策
若您的权利被侵害,请与我们联系处理,站长 QQ: 84087680 或 点击右侧 私信:盾给网 反馈,我们将尽快处理。
0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索