首页 > 其他分享 >@Transactional底层实现和失效场景

@Transactional底层实现和失效场景

时间:2024-03-18 14:25:08浏览次数:25  
标签:事务 Transactional 代理 回滚 失效 方法 public 底层

本文介绍下@Transactional底层实现和哪些场景会导致其失效

当使用@Transactional注解标注一个方法时,springboot会在运行时生成一个代理对象,该代理对象拦截被注解的方法调用,并在方法调用前后进行事务管理。事务管理包括开启事务、提交事务或者回滚事务等操作。

@Transactional实现思路如下:

@Transactional部分实现源码如下

 简单理解就是利用生成一个代理对象,然后去执行方法,如果出现异常那就自动回滚,否则就自动提交事务

 导致事务失效的场景有如下几个:

1、非public修饰的方法;

2、代码中使用try/catch处理的异常;

3、调用类内部的@Transactional方法;

4、数据库不支持事务。

解释下各个失效场景的原因:

1、非public修饰的方法:

① 浅层原因是@Transactional源码限制了必须是public才能执行后续代码流程,源码如下:

protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
        if (this.allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
            return null;
        }
        // 后续代码省略

所以@Transactional修饰方法是public才行

② 深层次原因 

深层次原因是 springboot动态代理只能代理公共方法,而不能代理私有方法或者受保护的方法。动态代理通常使用的是JDK动态代理和CGLib代理。JDK动态代理是基于接口实现的,基于接口实现的,接口方法也是需要public方法。CGlib是基于继承类,生成子类的,父类方法也是需要public。

所以动态代理底层机制所限,spring动态代理只能代理公共方法。

解决办法:使用public修饰方法

2、为什么代码中使用try-catch,事务不回滚了

是因为@Transactional在底层实现中,会捕捉异常,如果有了异常才有回滚,而程序中如果try-catch之后,它底层就感应不到异常,也就不会回滚事务,可以看下上面的底层源码实现

解决办法:要么就在catch中自己手动回滚代码(TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();)。或者业务代码模块可以catch捕捉异常,但是你要继续往外抛,能让它底层捕捉到异常,那才能回滚。

3、调用类内部的@Transactional方法为什么使事务失效

因为@Transactional是基于动态代理实现的,而调用类内部方法时是this对象实现的,这样就绕过了代理对象,从而事务失效了。

解决办法:可以在内部类上也添加@Transactional注解,这样就可以利用springboot隔离级别,让事务生效。

 

标签:事务,Transactional,代理,回滚,失效,方法,public,底层
From: https://www.cnblogs.com/qwg-/p/18080283

相关文章

  • Nginx底层基础数据结构
    基础数据结构ngx_int_t32位操作系统4字节,64位操作系统8字节解决跨平台以及,普通int类型在x86和x64操作系统上面是4字节,在类型转换时造成内存浪费(如在x64下面转换long类型)typedefintptr_tngx_int_t;#ifdef_WIN64typedef__int64intptr_t;#elsetype......
  • 数据结构之LinkedList底层代码全方位细节实现!
    题外话我很想发点nb的知识,但是路得一步一步走,饭也得一点一点吃,所以说不积跬步无以至千里,不积小流无以成江海!!!大家一起努力,未来属于我们!!正题理解链表相信大家看到这都应该明白链表,那就简单讲下链表组成今天实现LinkedList底层,LinkedList是一个双向链表,但是咱......
  • 学习JavaEE的日子 Day27 手撕HashMap底层原理
    Day271.手撕HashMap底层原理(重点)publicclassTest01{ publicstaticvoidmain(String[]args){ // Floatfloat1=newFloat("0.0f");// Floatfloat2=newFloat("0.0f");// Floatresult=float1/float2;// System.out.println(result);/......
  • 【业务功能篇】多环境配置、多数据源切换失效@DS解决方式
     多环境配置通过resources资源目录--config目录,我们分成了开发生产测试三个,不过一般我们都是测试环境进行测试数据库,本地开发环境就是连接测试环境 根据三个不同的环境,注意命名规范:application-xxx.yml,这样在我们的app配置文件就可以指定后缀这个值xxx就表示要运行哪个......
  • golang select底层原理
    select语句在Go语言中用于在多个通信操作(发送和接收)之间进行选择。在底层,Go运行时维护了关于每个case的状态信息,这些信息通常存储在scase结构体中。下面我将详细解释select语句的工作原理,并尝试用文字描述来模拟这一过程,因为直接在这里画图可能不太方便。首先,让我们回......
  • 面试官:说说反射的底层实现原理?
    反射是Java面试中必问的面试题,但只有很少人能真正的理解“反射”并讲明白反射,更别说能说清楚它的底层实现原理了。所以本文就通过大白话的方式来系统的讲解一下反射,希望大家看完之后能真正的理解并掌握“反射”这项技术。1.什么是反射?反射在程序运行期间动态获取类和操纵类的......
  • service层设置手动事务回滚,原因@Transactional事务与try{}catch(){}会失效,导事务不回
     1、原因是这样的,在service层的方法中,需要执行多条update或insert的数据操作,service的方法上是加@Transactional(rollbackFor=Exception.class)注解,然后方法体中又用了try{}catch(){}操作,导致在update多个执行时,其中有一条sql报错,本应该执行事务回滚操作报错前的update都不应......
  • SQL底层执行原理
    SQL底层执行原理#4.1SELECT语句的完整结构/*#sql92语法:SELECT....,....,....(存在聚合函数)FROM...,....,....WHERE多表的连接条件AND不包含聚合函数的过滤条件GROUPBY...,....HAVING包含聚合函数的过滤条件ORDERBY....,...(ASC/DESC)LIMIT...,....#sql99语法:SE......
  • Docker使用(三)Docker底层分析
    Docker使用(三)Docker底层分析四、底层分析1、Docker镜像原理1.1commit镜像dockercommit提交容器成为一个新的副本#命令和git原理类似dockercommit-m=“提交的描述信息”-a=“作者”容器id目标镜像名:[TAG]实操:#1、启动一个默认tomcat#2、发现这个默认......
  • 【已解决】Mybatis-plus中@TableLogic注解失效问题
    逻辑删除逻辑删除是指通过修改数据的状态或添加额外字段来表示数据的删除状态,而不是直接从数据库中物理删除数据记录。通常,会在数据库表中新增一个字段(如deleted),用来标识数据是否被删除。MyBatisPlus中实现逻辑删除在使用MyBatisPlus进行数据库操作时,实现逻辑删除......