@Transactional 注解失效情况及解决办法

2023-05-16

一、@Transactional 注解在了非 public 方法上

  1. 如下所示@Transactional修饰在了非public方法上
@Service
public class TestServiceImpl {

    @Resource
    private Test1Mapper test1Mapper;
    
    @Transactional
     protected Long save(Long seq){
        Long aLong = Optional.ofNullable(seq).orElse(System.currentTimeMillis());
        Test1Entity entity = new Test1Entity().setSeq(seq);
        test1Mapper.insert(entity);
        long l = entity.getId() / 0;
        return entity.getId();
    }
}

  1. 失效原因

    Spring 中是通过动态代理来实现注解了@Transactional的方法的事务处理操作,而在处理 @Transactional 的注解时是只对 public方法才有效。
    Spring 在扫描切点时,是根据注解进行判断是否创建切点。

    AopUtils#canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions)
    
    
    public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
        // .....
    	for (Class<?> clazz : classes) {
    		Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
    		for (Method method : methods) {
    			if (introductionAwareMethodMatcher != null ?
    					introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
    					// 此处判断是否匹配生成切面
    					methodMatcher.matches(method, targetClass)) {
    				return true;
    			}
    		}
    	}
    	return false;
    }
    
    
    TransactionAttributeSourcePointcut# matches(Method method, Class<?> targetClass)
    
    public boolean matches(Method method, Class<?> targetClass) {
    	TransactionAttributeSource tas = getTransactionAttributeSource();
    	// 获取 注解属性
    	return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
    }
    
    
    AnnotationTransactionAttributeSource#getTransactionAttribute
    AnnotationTransactionAttributeSource#computeTransactionAttribute
    
    @Nullable
    protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
    	// Don't allow no-public methods as required.
    	// 判断是否只允许 public 方法
    	if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
    		return null;
    	}
    
    	// 其他代码 ...
    	return null;
    }
    
    
  2. 解决方法

  • 方法一:把需要支持事务的方法统一定义为 public 修饰的方法
  • 方法二:创建一个全为public修饰的方法的门面类,在此类中添加@Transactional

二、在类内部调用添加 @Transactional 的方法

  1. 实例
@Service
public class TestServiceImpl {

   @Resource
   private Test1Mapper test1Mapper;

   @Transactional
    public void save(Long seq){
       Long aLong = Optional.ofNullable(seq).orElse(System.currentTimeMillis());
       test1Mapper.insert(new Test1Entity(null, seq));
       long l = aLong / 0;
   }

   // 调用内部方法
   public void innerInvoke(){
       this.save(100L);
   }
}

  1. 失效原因

此种情况跟情况一的原因类似,在Spring启动时会扫描所有添加了@Transactional注解的类,创建的切面,当在同一个类中调用是,切面失去了作用。

  1. 解决方法

既然事务管理是基于动态代理对象的代理逻辑实现的,那么如果在类内部调用类内部的事务方法,这个调用事务方法的过程并不是通过代理对象来调用的,而是直接通过this对象来调用方法,绕过的代理对象,肯定就是没有代理逻辑了。

如下所示:


@Service
public class TestServiceImpl {

    @Resource
    private Test1Mapper test1Mapper;

    // 第一个一个自己作为属性
    @Resource
    @Lazy
    private TestServiceImpl test1Service;

    @Transactional
     public void save(Long seq){
        Long aLong = Optional.ofNullable(seq).orElse(System.currentTimeMillis());
        test1Mapper.insert(new Test1Entity(null, seq));
        long l = aLong / 0;
    }

    // 调用内部方法
    public void innerInvoke(){
       //内部调用事务方法  
        test1Service.save(100L);
    }
}

三、捕获异常未抛出

  1. 实例

@Service
public class TestServiceImpl {

    @Resource
    private Test1Mapper test1Mapper;

    @Transactional
     public void save(Long seq){
        try {
            Long aLong = Optional.ofNullable(seq).orElse(System.currentTimeMillis());
            test1Mapper.insert(new Test1Entity(null, seq));
            long l = aLong / 0;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

  1. 失效原因

事务方法内部捕捉了异常,没有抛出新的异常,导致事务操作不会进行回滚。
这种的话,可能我们比较常见,问题就出在代理逻辑中,我们先看看源码里卖弄动态代理逻辑是如何为我们管理事务的。

  TransactionAspectSupport#invokeWithinTransaction

 protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)  
      throws Throwable {  
  
   // If the transaction attribute is null, the method is non-transactional.  
   final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);  
   final PlatformTransactionManager tm = determineTransactionManager(txAttr);  
   final String joinpointIdentification = methodIdentification(method, targetClass);  
  
   if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {  
      // Standard transaction demarcation with getTransaction and commit/rollback calls.  
       //开启事务  
      TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);  
      Object retVal = null;  
      try {  
         // This is an around advice: Invoke the next interceptor in the chain.  
         // This will normally result in a target object being invoked.  
          //反射调用业务方法  
         retVal = invocation.proceedWithInvocation();  
      }  
      catch (Throwable ex) {  
         // target invocation exception  
          //异常时,在catch逻辑中回滚事务  
         completeTransactionAfterThrowing(txInfo, ex);  
         throw ex;  
      }  
      finally {  
         cleanupTransactionInfo(txInfo);  
      }  
       //提交事务  
      commitTransactionAfterReturning(txInfo);  
      return retVal;  
   }  
  
   else {  
     //....................  
   }  
}  

  1. 解决方法
  • 方法一:在方法中不对异常进行捕获
  • 方法二:若必须捕获,在捕获处理后在重新抛出异常。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

@Transactional 注解失效情况及解决办法 的相关文章

  • 基于@Transactional注解的Spring事务

    64 Transactional注解 64 Transactional 可以作用于接口 接口方法 类以及类方法上 当作用于类上时 xff0c 该类的所有 public 方法将都具有该类型的事务属性 xff0c 同时 xff0c 我们也可以在
  • @Transactional 注解失效情况及解决办法

    一 64 Transactional 注解在了非 public 方法上 如下所示 64 Transactional修饰在了非public方法上 span class token annotation punctuation 64 Servi
  • jeecgboot @Transactional捕获异常并拿到返回值

    64 Transactional 和 64 RestControllerAdvice 并不冲突 回滚的同时拦截异常返回需要的值给前端 64 Override 64 Transactional rollbackFor 61 Exception
  • @Transactional 详解

    前些天发现了一个巨牛的人工智能学习网站 xff0c 通俗易懂 xff0c 风趣幽默 xff0c 忍不住分享一下给大家 点击跳转到教程 64 Transactional 是声明式事务管理 编程中使用的注解 1 添加位置 1 xff09 接口实
  • @Transactional注解事务失效的七种原因分析

    64 Transactional是一种基于注解管理事务的方式 xff0c spring通过动态代理的方式为目标方法实现事务管理的增强 64 Transactional使用起来方便 xff0c 但也需要注意引起 64 Transactiona
  • 第二篇:Spring Boot整合JPA、事务处理及AOP的使用

    一 Spring Boot整合JPA的具体步骤 注 Spring Boot整合JPA 源码下载 注 springboot学习资料汇总 参考 spring data jpa的使用 参考 Spring Cloud微服务实战 作者 参考 方志朋博
  • 关于Springboot 无法捕获异常(@Transactional注解导致)

    在工作中发现了一个非常奇怪的事情 就是我突然间捕获不了异常 异常捕获 关于为什么会出现这样的问题呢 经过研究发现 原来是在这个类上 被加上了事务的注解 Transactional 这个事务的注解 就把我的异常给处理掉了 所以在这个被事务注解
  • SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@xxx] was not registered for synchro

    目录 1 报错场景 2 问题原因及解决办法 1 报错场景 在搞SpringBoot项目的时候 把Mybatis打印日志的配置打开后 发现每条Sql打印的时候都会在前面打印如下的信息 强迫症受不了 得查查为什么 Creating a new
  • 如何扩展Spring注解@Transactional

    我必须在我的网络应用程序中使用 3 个不同的事务管理器 所以我根据以下内容编写了自己的注释弹簧参考 第 10 5 6 3 节自定义快捷方式注释 一个注释 用于使用一个特定的事务管理器 如下所示 import java lang annota
  • 事务性保存而不调用更新方法

    我有一个用 Transactional 注释的方法 我从 Oracle DB 检索一个对象 更改一个字段 然后从该方法返回 我忘记保存对象 但发现数据库无论如何都会更新 应用上下文
  • Spring事务上下文不持久保存数据

    我知道我的问题是一个常见问题 但是我在这里检查了很多问题 检查了Spring文档 我真的不知道我做错了什么 我的问题 我有一个使用 JPA 的 Spring WebFlow 项目 实现 OpenJPA MySQL 数据库 我使用 Sprin
  • 集中回滚-用于使用@transactional

    是否可以告诉Spring回滚异常MyException也RuntimeException使用时在 XML 配置中 transactional 我知道可以在注释中设置回滚 但如果我有很多服务都设置相同的异常 那么这似乎是多余的 我看到人们建议
  • 在 Scala 中使用 Spring @Transactional

    我们有一个混合 Java 和 Scala 的项目 它使用 Spring 事务管理 我们使用 Spring 方面将文件与 Transactional 带注释的方法编织在一起 问题是 Scala 类没有与 Spring 事务方面交织在一起 如何
  • Jersey、Guice 和 Hibernate - EntityManager 线程安全

    我在我的应用程序中以同样的方式使用了本教程 http www benmccann com hibernate with jpa annotations and guice http www benmccann com hibernate w
  • Spring、事务、Hibernate 过滤器

    我在 Spring 中使用声明式事务 我有一个带有 事务性 注释的服务层 该服务层调用 DAO 我需要在所有 dao 方法中启用 hibernate 过滤器 我不想每次都显式调用 session enablefilter 那么有没有一种方法
  • @Transactional Spring MyBatis 不工作

    我有一个 Spring Web 应用程序 一切都很好 但现在我需要一种方法来进行事务处理 这是我的 applicationContext xml
  • Seam @Transactional 注释不起作用?

    我在接缝组件上使用 Transactional 注释 类似于 Name myComponent AutoCreate public class MyComponent public void something doWork Transac
  • 如何使用事务范围的持久化上下文进行非事务性读取查询?

    我读了 Spring 文档 它说 PersistenceContext 注解有一个可选的属性类型 默认为 PersistenceContextType TRANSACTION 此默认值是您接收共享所需的 实体管理器代理 这是否意味着我必须让
  • @Transactional 方法调用另一个没有 @Transactional 注解的方法?

    我在 Service 类中看到了一个方法 该方法被标记为 Transactional 但它还调用同一类中的一些其他方法 这些方法未标记为 Transactional 这是否意味着对单独方法的调用导致应用程序打开与数据库的单独连接或挂起父事务
  • Spring @Retryable 与有状态 Hibernate 对象

    我正在尝试使用 Springs Retryable 让我的服务方法在失败时重试 Retryable backoff Backoff delay 1000 maxAttempts 3 Transactional rollbackFor Thr

随机推荐

  • 多线程编程模式之Single Threaded Execution 模式

    一 Single Threaded Execution 模式介绍 简单的来说 xff0c Single threaded execution 模式描述了在一种多线程环境下各个线程对于公用资源的使用方式 任一时刻 xff0c 只有一个线程可以
  • NVIDIA Jetson TX2 查看系统相关+运行demo

    1 查看Jetson TX2 L4T版本 xff1a head n 1 etc nv tegra release 2 查看系统版本 xff1a cat etc lsb release 3 查看系统内核 xff1a uname a 4 查看内
  • Docker镜像迁移至新的服务器(全部数据)

    1 找到你想移动的 Docker 容器的 ID 2 提交你的变更 xff0c 并且把容器保存成镜像 xff0c 命名为 newimage docker commit span class token number 3 span a09b25
  • 配置VNC环境在windows主机访问阿里云linux服务器

    配置VNC环境在windows主机访问阿里云linux服务器 虽然作为服务器使用更多的是使用字符终端连接服务器 xff0c 进行操作 xff0c 因为图形界面很消耗性能和资源 xff0c 但有的时候使用图形界面进行操作更为便捷 xff0c
  • pythondataframe输出小结

    在使用dataframe时遇到datafram在列太多的情况下总是自动换行显示的情况 xff0c 导致数据阅读困难 xff0c 效果如下 xff1a coding utf 8 import numpy as np import pandas
  • 聊聊 Redis 为什么构建自己的简单动态字符串 SDS

    我们知道 xff0c Redis 支持字符串 哈希 列表 集合和有序集合五种基本类型 那么我们如何把图片 音频 视频或者压缩文件等二进制数据保存到 Redis 中呢 xff1f 之前在使用 Memcached 缓存这类数据时是把它们转换成
  • 聊聊 Redis 高可用之持久化AOF和RDB分析

    Redis 持久化概述 Redis 是内存数据库 xff0c 数据都是存储在内存中 xff0c 为了避免进程退出导致数据的永久丢失 xff0c 需要定期将 Redis 中的数据以某种形式把内存中的数据保存到磁盘中 xff1b 当 Redis
  • mysqldump: Got error: 1044: Access denied for user XXXX when doing LOCK TABLES

    一 报错信息 在使用mysqldump 执行远程备份数据库的时候报如下错误 xff1a mysqldump Got error span class token number 1044 span Access denied span cla
  • jmap -heap [pid]运行报:Error attaching to process: sun.jvm.hotspot.debugger.DebuggerException(不允许的操作)

    一 运行环境 操作系统 xff1a Ubuntu 5 4 0 6 Java版本 xff1a JDK8 二 执行命令 jmap heap span class token punctuation span pid号 span class to
  • chkconfig: command not found

    问题描述 在 ubuntu1 16 04 10 执行 chkconfig 命令报 chkconfig command not found 说明此服务上没有安装 chkconfig 执行如下命令进行安装 span class token fu
  • Docker 基础篇 之 安装

    一 Docker安装 查看 CentOS 内核版本 Docker 要求 CentOS 系统的内核版本高于3 10 执行如下命令查询 内核版本 span class token function uname span r span class
  • Java 基础 之 Valid 验证

    一 64 Valid 简介 Bean Validation 内置的校验器 校验器说明 64 Null被注解的元素必须为 null 64 NotNull被注解的元素必须不为 null 64 AssertTrue被注解的元素必须为 true 6
  • HttpURLConnection链接详解

    HttpURLConnection链接详解 一 简介 简单来说 xff0c HttpURLConnection 是 Java 提供的发起 HTTP 请求的基础类库 xff0c 提供了 HTTP 请求的基本功能 xff0c 不过封装的比较少
  • Apache HttpClient 详解

    1 简介 HttpClient 是 Apache Jakarta Common 下的子项目 xff0c 用来提供高效的 最新的 功能丰富的支持 HTTP 协议的客户端编程工具包 xff0c 并且它支持 HTTP 协议最新的版本和建议 Htt
  • OKHttp使用详解

    1 简介 OkHttp 是一个默认高效的 HTTP 客户端 xff1a HTTP 2 支持允许对同一主机的所有请求共享一个套接字 连接池减少了请求延迟 xff08 如果 HTTP 2 不可用 xff09 透明 GZIP 缩小了下载大小 响应
  • python二维码生成与扫码

    1 import qrcode img 61 qrcode make 34 hello world 34 img get image show img save 39 hello png 39 2 import qrcode qr 61 q
  • C语言可变参数(从stdarg.h到应用)

    1 什么是可变参数函数 在C语言编程中有时会遇到一些参数可变的函数 xff0c 例如printf scanf xff0c 其函数原型为 xff1a span class token keyword int span span class t
  • OkHttp 缓存实战

    1 简介 在实际业务中可能某些查询数据 xff0c 不经常变化 xff0c 为了节省流量 提高响应速度和增强用户体验等 xff0c 把变化频率小的数据缓存到本地 xff0c 以实现复用 OkHttp 的缓存功能使用起来也比较简单和灵活 xf
  • Feign 详解

    1 Feign 是什么 Feign是一个http请求调用的轻量级框架 xff0c 可以以Java接口注解的方式调用Http请求 Feign通过处理注解 xff0c 将请求模板化 xff0c 当实际调用的时候 xff0c 传入参数 xff0c
  • @Transactional 注解失效情况及解决办法

    一 64 Transactional 注解在了非 public 方法上 如下所示 64 Transactional修饰在了非public方法上 span class token annotation punctuation 64 Servi