当前位置: 首页 > article >正文

【Spring声明式事务失效的12种场景测试】

文章目录

    • 一.Spring声明式事务是什么?
    • 二.Spring事务失效的12种场景
      • 1.访问权限问题
    • 小结

一.Spring声明式事务是什么?

Spring声明式事务是一种通过配置的方式管理事务的方法,它通过注解或XML配置来声明哪些方法需要事务管理,从而将事务管理逻辑与业务逻辑分离,简化了代码的复杂度,提高了代码的可读性和可维护性。‌

声明式事务的核心在于通过AOP(面向切面编程)技术实现事务管理的自动化。开发者只需在需要事务管理的方法上添加@Transactional注解,Spring框架会自动在方法执行前后进行事务的开启和关闭,以及在出现异常时进行事务的回滚。这种方式使得开发者可以专注于业务逻辑的实现,而不需要编写繁琐的事务管理代码‌。

具体实现方式上,声明式事务可以通过注解或XML配置来实现。使用注解方式时,只需在方法上添加@Transactional注解,Spring会自动处理事务的开启、提交和回滚。使用XML配置方式时,需要在Spring配置文件中进行相应的配置,指定哪些方法需要事务管理。这两种方式都使得事务管理的细节被屏蔽,开发者无需关心事务的具体实现细节‌

二.Spring事务失效的12种场景

在这里插入图片描述
我们在前面文章中了解过Spring编程式事务,看过Spring声明式事务源码的小伙伴们应该也清楚Spring声明式事务底层是借助于AOP+声明式事务去做的。我们知道Mybatis是基于数据源的方式,其编程式事务依赖于PlatformTransactionManager接口的实现DataSourceTransactionManager事务管理器进行事务管理(开启、提交、回滚)的。
所以我们使用Spring声明式事务需要往Spring容器中注入事务管理器所需的相关bean信息。

//在Spring开启声明式事务支持时,启动类需要加@EnableTransactionManagement注解。‌ 
//这个注解告诉Spring容器要启用基于注解的事务管理功能,否则事务不生效
@EnableTransactionManagement
@ComponentScan({"com.jinbiao.spring_study.transactionTest"})
@Configuration
public class JDBCConfig {
    @Bean
    public DataSource dataSource(){
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
        druidDataSource.setUrl("jdbc:mysql://localhost:3306/study_test");
        druidDataSource.setUsername("root");
        druidDataSource.setPassword("123456");
        return druidDataSource;
    }

    /**
     * 如果使用到mybatis需要给sqlSessionFactoryBean注入数据源信息
     * @param dataSource
     * @return
     */
    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        return sqlSessionFactoryBean;
    }

    @Bean
    public JdbcTemplate jdbcTemplate(){
       return new JdbcTemplate(dataSource());
    }

    @Bean
    public PlatformTransactionManager transactionManager(){
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource());
        return transactionManager;
    }
}

1.访问权限问题

事务方法使用 final 、static 修饰方法。
static 静态方法属于类本身的而非实例,代理对象是无法对静态方法进行代理或拦截的。

小伙伴们仔细想想,静态方法是在构造方法之前执行的,对象是通过构造方法创建的,jdk动态代理或者cglb动态代理都是针对目标对象增强生成代理对象。这样一想静态方法怎么被代理对象增强对吧!(说人话:静态方法被调用的时候,对象都还没创建,代理对象都还没出生呢,所以事务怎么生效对吧~)

  • 测试事务方法使用static 修饰,无法回滚问题。
  1. 错误的测试方式:
   @Autowired
    private static JdbcTemplate jdbcTemplate;

    /**
     * 测试事务失效1:访问权限问题:事务方法使用 static修饰方法
     */
    @Transactional
    public static void test1() {
        /**
         * 静态方法里面直接从Spring容器里面取jdbcTemplate此时会为null,会报空指针
         * 需要用在bean初始化前方法里面填充好的userServiceTransaction对象的jdbcTemplate。
         */
        jdbcTemplate.execute("insert into jinbiao_user values (1,'rise1','wang1234..','10086','小程序')");
        throw new RuntimeException("异常啦,请回滚...");
    }

静态方法只能调用静态属性(不然程序编译期报错),我们注入的时候,把Spring容器里面的这个jdbcTemplate 使用static修饰升级为类变量,会报空指针,原理上面已解释:静态方法被调用的时候,对象都还没创建当然报空指针。
在这里插入图片描述
2. 正确的测试方式:

  1. 在Spring生命周期中,@PostConstruct注解的方法是在属性填充之后执行的,此时的this是填充好属性jdbcTemplate的。
  2. 所以我们在bean初始化前方法里面用填充好属性的this对象赋值给静态成员变量userServiceTransaction
  3. 通过静态成员变量userServiceTransaction的属性jdbcTemplate来执行sql。
 	@Autowired
    public static UserServiceTransaction userServiceTransaction;
    
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @PostConstruct
    public void init(){
        userServiceTransaction = this;
    }

    /**
     * 测试事务失效1:访问权限问题:事务方法使用 static修饰方法
     */
    @Transactional
    public static void test1() {
        /**
         * 静态方法里面直接从Spring容器里面取jdbcTemplate此时会为null,会报空指针
         * 需要用在bean初始化前方法里面填充好的userServiceTransaction对象的jdbcTemplate。
         */
        userServiceTransaction.jdbcTemplate.execute("insert into jinbiao_user values (1,'rise1','wang1234..','10086','小程序')");
        throw new RuntimeException("异常啦,请回滚...");
    }

测试结果:数据没回滚。
在这里插入图片描述

  • 测试事务方法使用final 修饰,无法回滚问题。
    final 修饰的方法不能被子类重写,事务相关的逻辑无法插入到 final 方法中,代理机制无法对 final 方法进行拦截或增强。

下班了,未完持续….

小结


http://www.kler.cn/news/355749.html

相关文章:

  • Redis 数据类型Bitmaps(位图)
  • ES-入门-javaApi-文档-新增-删除
  • 【芙丽芳丝净润洗面霜和雅漾舒护活泉喷雾
  • AnaTraf | TCP重传的工作原理与优化方法
  • 【数据分享】1901-2023年我国省市县三级逐月最低气温(免费获取/Shp/Excel格式)
  • 详解tcpdump
  • (4) cuda cudnn TensorRT安装及配置
  • Qt(信号槽)
  • 等保测评与网络安全应急响应
  • uni-app 实现好看易用的抽屉效果
  • 实时计算Flink应用场景
  • PMP--必刷题–解题–161-172
  • python编程:常用模块分类整理
  • 打包使用pythn编写的maya插件,使用pyeal打包
  • Karmada核心概念
  • beyond compare 这个授权密钥已被吊销
  • Lucene 倒排索引
  • 5.深度学习计算
  • 【MR开发】在Pico设备上接入MRTK3(二)——在Unity中配置Pico SDK
  • 利用Arcgis进行沟道形态分析