事务注解失效的六种场景

事务注解失效的六种场景

环境搭建

sql

CREATE TABLE `student` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `name` varchar(255) DEFAULT NULL COMMENT '姓名',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=162 DEFAULT CHARSET=utf8;

pom

 <dependencies>
       <!-- spring框架运行的必须jar包 -->
       <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-context</artifactId>
           <version>5.0.2.RELEASE</version>
       </dependency>
       <!-- spring框架对于jdbc进行的简单封装 -->
       <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-jdbc</artifactId>
           <version>5.0.2.RELEASE</version>
       </dependency>
       <!-- spring框架对于事务支持的jar包 -->
       <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-tx</artifactId>
           <version>5.0.2.RELEASE</version>
       </dependency>
       <!-- spring框架的测试包 -->
       <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-test</artifactId>
           <version>5.0.2.RELEASE</version>
       </dependency>
       <!-- spring框架提供对AspectJ框架的整合 -->
       <dependency>
           <groupId>org.aspectj</groupId>
           <artifactId>aspectjweaver</artifactId>
           <version>1.8.7</version>
       </dependency>
       <!-- mysql数据库 -->
       <dependency>
           <groupId>mysql</groupId>
           <artifactId>mysql-connector-java</artifactId>
           <version>5.1.6</version>
       </dependency>
       <!-- 测试 -->
       <dependency>
           <groupId>junit</groupId>
           <artifactId>junit</artifactId>
           <version>4.12</version>
       </dependency>
       <dependency>
           <groupId>org.projectlombok</groupId>
           <artifactId>lombok</artifactId>
           <version>1.16.4</version>
       </dependency>
   </dependencies>

配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!-- 配置spring提供的数据库连接池 -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/spring"></property>
        <property name="username" value="root"></property>
        <property name="password" value="123456"></property>
    </bean>

    <!-- jdbcTemplate的配置 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <context:component-scan
            base-package="com"></context:component-scan>

    <!-- 配置事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 启用事务注解 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

1 方法修饰是protected和provite

/**
     * protected  事务会失效
     * private    不允许添加事务注解
     */
    @Transactional
    protected   void  addProtected(Student student){
        jdbcTemplate.update("insert into student (name) values (?);",
                student.getName());
        int i=1/0;
    }

2 rollback设置错误

/**
     * 设置异常 事务失效
     * @param student
     * @throws FileNotFoundException
     */
    @Transactional(rollbackFor = Exception.class)
    public  void  addRollBackFor(Student student) throws FileNotFoundException {
        // @Transactional
        studentService.add(student);
        //事务失效
        throw  new  FileNotFoundException("");
    }

3 异常信息被捕获

/**
     * 异常捕获 事务失效
     * @param student
     */
    @Transactional
    public void addTryCatch(Student student) {

        try {
            studentService.add(student);
            int i=1/0;
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
    }

4 同类之间方法调用

 /**
     * 
     * 这种场景复现有一个坑 可以使用REQUIRED和REQUIRES_NEW 配合使用
     * @param student
     */
    @Transactional
    public void addBySameClass(Student student) {
      /*  addError(student);等价于 jdbcTemplate.update("insert into student (name) values (?);",
                student.getName());*/
        //注释的代码无法复现 需要使用下面的方法
        studentService.addError(student);
        throw  new RuntimeException("");
    }
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void addError(Student student) {
        jdbcTemplate.update("insert into student (name) values (?);",
                student.getName());

    }

5 传播行为配置错误

5.1 传播行为是SUPPORTS
 /**
     * 自身不支持事务
     * @param student
     */
    @Transactional(propagation = Propagation.SUPPORTS)
    public  void addBySupports(Student student){
        jdbcTemplate.update("insert into student (name) values (?);",
                student.getName());
        int i=1/0;
    }
5.2 传播行为是NOT_SUPPORTED
 @Transactional
    public  void  addByNotSupportsTest(Student student){
    // addByNotSupports(student); // 这样是有事务的
       studentService.addByNotSupports(student);
    }

    /**
     * NOT_SUPPORTED 已非事务状态运行
     * @param student
     */
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public  void addByNotSupports(Student student){
        jdbcTemplate.update("insert into student (name) values (?);",
                student.getName());
        int i=1/0;
    }
5.3 传播行为是NEVER
 /**
     * NEVER 已非事务状态运行  存在事物就抛出异常信息
     * @param student
     */
    @Transactional(propagation = Propagation.NEVER)
    public  void addByNever(Student student){
        jdbcTemplate.update("insert into student (name) values (?);",
                student.getName());
    }

    @Transactional
    public  void  addByNeverTest(Student student){
        //addByNever(student); 这种场景是无法验证的
        studentService.addByNever(student);
    }

6 存储引擎本身不支持事务

Myisam该存储引擎自身不支持事务

代码地址

https://gitee.com/baizeze/transactional.git
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
@Transactional注解失效场景有以下几种情况: 1. 异常被catch并处理: 当一个使用@Transactional注解标记的方法中发生异常时,如果异常被catch并在方法内部进行了处理,那么事务将不会回滚。这是因为Spring默认只会对未被捕获的异常进行回滚处理。 2. 事务方法内部调用其他事务方法: 如果一个使用@Transactional注解标记的方法内部调用了另一个使用@Transactional注解标记的方法,而内部方法没有抛出异常,则外部方法的事务将无效。原因是Spring默认使用了基于代理的事务机制,而代理是通过AOP实现的。在同一个类中,使用@Transactional注解标记的方法调用其他使用@Transactional注解标记的方法,事务失效。 3. 基于自调用的事务: 当一个使用@Transactional注解标记的方法内部调用了自身(即自循环),而且没有使用代理的方式进行调用,事务也会失效。这是因为代理是通过AOP实现的,自调用会绕过代理,导致事务无法生效。 4. 异步方法: 在使用Spring的异步方法时,如果在异步方法内部使用了@Transactional注解标记的方法,事务将无效。这是因为异步方法会在一个新的线程中执行,而事务是基于线程的。因此,在异步方法中使用事务注解是无效的。 5. protected或private方法: 当使用@Transactional注解标记的方法是protected或private修饰的时候,事务也会失效。尽管没有报错,但事务并不会起作用。这是一个常见的错误点,需要特别注意。 综上所述,需要注意以上情况,以确保@Transactional注解的正确使用和事务的生效。如果遇到上述场景,可以考虑使用其他方式来实现事务控制,如编程式事务管理或通过代理对象调用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值