@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 的配置文件中未配置事务注解生效

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

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

简单分析一下:

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

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

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

  1. org.springframework.jdbc.datasource.DataSourceTransactionManager

它继承自

  1. org.springframework.transaction.support.AbstractPlatformTransactionManager

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

 

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

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

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

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

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

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

  1. //If the transaction attribute is null, the method is non-transactional.
  2. final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
  1. // First try is the method in the target class.
  2. TransactionAttribute txAtt = findTransactionAttribute(specificMethod);
  3. if (txAtt != null) {
  4. return txAtt;
  5. }
  6. // Second try is the transaction attribute on the target class.
  7. txAtt = findTransactionAttribute(specificMethod.getDeclaringClass());
  8. if (txAtt != null) {
  9. return txAtt;
  10. }
  11. if (specificMethod != method) {
  12. // Fallback is to look at the original method.
  13. txAtt = findTransactionAttribute(method);
  14. if (txAtt != null) {
  15. return txAtt;
  16. }
  17. // Last fallback is the class of the original method.
  18. return findTransactionAttribute(method.getDeclaringClass());
  19. }

事务信息通过 createTransactionIfNecessary 方法创建

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

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

  1. completeTransactionAfterThrowing(txInfo, ex);

根据注解参数 rollback

  1. if (txInfo.transactionAttribute.rollbackOn(ex)) {
  2. try {
  3. txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
  4. }
  5. catch (TransactionSystemException ex2) {
  6. logger.error("Application exception overridden by rollback exception", ex);
  7. ex2.initApplicationException(ex);
  8. throw ex2;
  9. }
  10. catch (RuntimeException ex2) {
  11. logger.error("Application exception overridden by rollback exception", ex);
  12. throw ex2;
  13. }
  14. catch (Error err) {
  15. logger.error("Application exception overridden by rollback error", ex);
  16. throw err;
  17. }
  18. }

根据注解参数 commit

  1. else {
  2. // We don't roll back on this exception.
  3. // Will still roll back if TransactionStatus.isRollbackOnly() is true.
  4. try {
  5. txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
  6. }
  7. catch (TransactionSystemException ex2) {
  8. logger.error("Application exception overridden by commit exception", ex);
  9. ex2.initApplicationException(ex);
  10. throw ex2;
  11. }
  12. catch (RuntimeException ex2) {
  13. logger.error("Application exception overridden by commit exception", ex);
  14. throw ex2;
  15. }
  16. catch (Error err) {
  17. logger.error("Application exception overridden by commit error", ex);
  18. throw err;
  19. }
  20. }
  21. }

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

  1. commitTransactionAfterReturning(txInfo);

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

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管理员
欢迎您,新朋友,感谢参与互动!
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
私信列表
搜索