@Transactional事务注解的传播性

1、在常见的事务管理框架中,有以下几种事务传递的方式:

(1)REQUIRED:默认的传播行为。如果方法A在事务中被调用,并且方法A调用了方法B,则方法B将会加入到同一个事务中。如果方法A没有事务上下文,则会创建一个新的事务。

(2)REQUIRES_NEW:无论方法A是否在事务中被调用,方法B都会创建一个新的事务,并在方法B执行完毕后提交该事务。如果方法A已经存在事务,那么方法A的事务将被挂起,直到方法B的事务完成。

(3)SUPPORTS:如果方法A在事务中被调用,则方法B将加入到同一个事务中。如果方法A没有事务上下文,则方法B将以非事务方式执行。

(4)NOT_SUPPORTED:方法B将以非事务方式执行,即使方法A在事务中被调用。

(5)MANDATORY:如果方法A在事务中被调用,则方法B将加入到同一个事务中。如果方法A没有事务上下文,则会抛出异常。

(6)NEVER:如果方法A在事务中被调用,则会抛出异常。

(7)NESTED:如果方法A在事务中被调用,并且方法A调用了方法B,则方法B将在一个嵌套事务中执行。嵌套事务是外部事务的一部分,可以独立提交或回滚,但只有当外部事务成功提交时,嵌套事务才会被提交。

    这些传播行为可以根据具体的需求来选择,以实现不同的事务传递行为。需要根据具体的业务场景和需求来决定使用哪种事务传递方式。

2、以下是代码案例

(1)对应SQL

CREATE TABLE `rb_order` (
  `id` varchar(100) NOT NULL COMMENT '主键',
  `order_name` varchar(100) DEFAULT NULL COMMENT '订单名称',
  `order_price` varchar(100) DEFAULT NULL COMMENT '订单价格',
  `tr_introduce` varchar(100) DEFAULT NULL COMMENT '事物描述',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE `rb_user` (
  `id` varchar(100) NOT NULL,
  `name` varchar(100) DEFAULT NULL,
  `password` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

(2)对应entity实体

@Data
@TableName("rb_order")
public class RbOrder {

    @TableId(type = IdType.ASSIGN_UUID)
    private String id;

    private String orderName;

    private String orderPrice;

    private String trIntroduce;
}


@Data
@TableName("rb_user")
public class RbUser {

    @TableId(type = IdType.ASSIGN_UUID)
    private String id;

    private String name;

    private Integer password;

}

(3)对应mapper文件

@Mapper
public interface RbOrderMapper extends BaseMapper {
}

@Mapper
public interface RbUserMapper extends BaseMapper {
}

(4)对应service文件:

public interface RbOrderService extends IService {
}

public interface RbUserService extends IService {
}

(5)对应serviceImpl文件

@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class RbOrderServiceImpl extends ServiceImpl implements RbOrderService {
}

@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class RbUserServiceImpl extends ServiceImpl implements RbUserService {
}

(6)对应service biz业务类

@Slf4j
@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class TransactionalBizService {

    private final RbUserService rbUserService;
    private final RbOrderService rbOrderService;


    /**
     * 事务操作 - 默认的传播行为。如果方法A在事务中被调用,并且方法A调用了方法B,则方法B将会加入到同一个事务中。如果方法A没有事务上下文,则会创建一个新的事务
     * 现象 - RbUser数据回滚,RbOrder数据回滚
     *
     * @return void
     * @Author 俞春旺
     * @Date 上午 11:48:14 2023年6月19日 0019
     **/
    @Transactional(rollbackFor = Exception.class)
    public void transactional1() {
        // 构建 - 事务保存对象
        RbUser transactional1 = this.convertUser("transactional1");
        // 操作 - 保存用户数据
        boolean save = rbUserService.save(transactional1);
        Assert.isTrue(save, "保存失败");

        // 操作 - 新增订单数据,方法带入:@Transactional(rollbackFor = Exception.class)
        SpringUtil.getBean(TransactionalBizService.class).saveOrderTransactionalRequired();

        // 代码模拟操作失败
        Assert.isTrue(false, "数据报错");
    }

    /**
     * 事务操作 - 默认的传播行为。如果方法A在事务中被调用,并且方法A调用了方法B,则方法B将会加入到同一个事务中。如果方法A没有事务上下文,则会创建一个新的事务
     * 现象 - RbUser数据回滚,RbOrder正常创建数据
     *
     * @return void
     * @Author 俞春旺
     * @Date 上午 11:48:14 2023年6月19日 0019
     **/
    @Transactional(rollbackFor = Exception.class)
    public void transactional2() {
        // 构建 - 事务保存对象
        RbUser transactional2 = this.convertUser("transactional2");
        // 操作 - 保存用户数据
        boolean save = rbUserService.save(transactional2);
        Assert.isTrue(save, "保存失败");

        // 操作 - 新增订单数据,方法带入:@Transactional(rollbackFor = Exception.class)
        // 操作 - 事物不生效:事务方法被同一个类中的其他方法调用:默认情况下,事务是通过AOP切面来实现的。如果在同一个类中的一个方法调用另一个带有@Transactional注解的方法,事务可能不会生效。这是因为AOP切面是通过代理来实现的,代理对象无法截获同一个类内部方法的调用。为了解决这个问题,可以通过将注解添加到另一个类中的方法来实现事务传播
        // this.saveOrderTransactionalRequiredNew();
        SpringUtil.getBean(TransactionalBizService.class).saveOrderTransactionalRequiredNew();
        // 代码模拟操作失败
        Assert.isTrue(false, "数据报错");
    }

    /**
     * 事务操作 - 如果方法A在事务中被调用,则方法B将加入到同一个事务中。如果方法A没有事务上下文,则方法B将以非事务方式执行。
     * 现象 - RbUser数据回滚,RbOrder数据回滚
     *
     * @return void
     * @Author 俞春旺
     * @Date 上午 11:48:14 2023年6月19日 0019
     **/
    @Transactional(rollbackFor = Exception.class)
    public void transactional3() {
        // 构建 - 事务保存对象
        RbUser transactional3 = this.convertUser("transactional3");
        // 操作 - 保存用户数据
        boolean save = rbUserService.save(transactional3);
        Assert.isTrue(save, "保存失败");

        // 操作 - 新增订单数据,方法带入:@Transactional(rollbackFor = Exception.class)
        SpringUtil.getBean(TransactionalBizService.class).saveOrderTransactionalSupports();
    }

    /**
     * 事务操作 - 如果方法A在事务中被调用,则方法B将加入到同一个事务中。如果方法A没有事务上下文,则方法B将以非事务方式执行。
     * 现象 - RbUser正常创建,RbOrder正常创建
     *
     * @return void
     * @Author 俞春旺
     * @Date 上午 11:48:14 2023年6月19日 0019
     **/
    public void transactional3_1() {
        // 构建 - 事务保存对象
        RbUser transactional3 = this.convertUser("transactional3");
        // 操作 - 保存用户数据
        boolean save = rbUserService.save(transactional3);
        Assert.isTrue(save, "保存失败");

        // 操作 - 新增订单数据,方法带入:@Transactional(rollbackFor = Exception.class)
        SpringUtil.getBean(TransactionalBizService.class).saveOrderTransactionalSupports();
    }

    /**
     * 事务操作 - 方法B将以非事务方式执行,即使方法A在事务中被调用。
     * 现象 - RbUser数据回滚,RbOrder正常插入
     *
     * @return void
     * @Author 俞春旺
     * @Date 上午 11:48:14 2023年6月19日 0019
     **/
    @Transactional(rollbackFor = Exception.class)
    public void transactional4() {
        // 构建 - 事务保存对象
        RbUser transactional4 = this.convertUser("transactional4");
        // 操作 - 保存用户数据
        boolean save = rbUserService.save(transactional4);
        Assert.isTrue(save, "保存失败");

        // 操作 - 新增订单数据,方法带入:@Transactional(rollbackFor = Exception.class)
        SpringUtil.getBean(TransactionalBizService.class).saveOrderTransactionalNotSupports();
        // 代码模拟操作失败
        Assert.isTrue(false, "数据报错");
    }

    /**
     * 事务操作 - 如果方法A在事务中被调用,则方法B将加入到同一个事务中。如果方法A没有事务上下文,则会抛出异常。
     * 现象 - RbUser数据回滚,RbOrder数据回滚
     *
     * @return void
     * @Author 俞春旺
     * @Date 上午 11:48:14 2023年6月19日 0019
     **/
    @Transactional(rollbackFor = Exception.class)
    public void transactional5() {
        // 构建 - 事务保存对象
        RbUser transactional5 = this.convertUser("transactional5");
        // 操作 - 保存用户数据
        boolean save = rbUserService.save(transactional5);
        Assert.isTrue(save, "保存失败");

        // 操作 - 新增订单数据,方法带入:@Transactional(rollbackFor = Exception.class)
        SpringUtil.getBean(TransactionalBizService.class).saveOrderTransactionalMandatory();
        // 代码模拟操作失败
        Assert.isTrue(false, "数据报错");
    }

    /**
     * 事务操作 - 如果方法A没有事务上下文,则会抛出异常。
     * 现象 - RbUser正常创建,RbOrder数据回滚
     *
     * @return void
     * @Author 俞春旺
     * @Date 上午 11:48:14 2023年6月19日 0019
     **/
    public void transactional5_1() {
        // 构建 - 事务保存对象
        RbUser transactional5_1 = this.convertUser("transactional5_1");
        // 操作 - 保存用户数据
        boolean save = rbUserService.save(transactional5_1);
        Assert.isTrue(save, "保存失败");

        // 操作 - 新增订单数据,方法带入:@Transactional(rollbackFor = Exception.class)
        SpringUtil.getBean(TransactionalBizService.class).saveOrderTransactionalMandatory();
        // 代码模拟操作失败
        Assert.isTrue(false, "数据报错");
    }

    /**
     * 事务操作 - 如果方法A在事务中被调用,则会抛出异常。
     * 现象 - RbUser正常创建,RbOrder数据回滚
     *
     * @return void
     * @Author 俞春旺
     * @Date 上午 11:48:14 2023年6月19日 0019
     **/
    @Transactional(rollbackFor = Exception.class)
    public void transactional6() {
        // 构建 - 事务保存对象
        RbUser transactional6 = this.convertUser("transactional6");
        // 操作 - 保存用户数据
        boolean save = rbUserService.save(transactional6);
        Assert.isTrue(save, "保存失败");

        // 操作 - 新增订单数据,方法带入:@Transactional(rollbackFor = Exception.class)
        SpringUtil.getBean(TransactionalBizService.class).saveOrderTransactionalNever();
        // 代码模拟操作失败
        Assert.isTrue(false, "数据报错");
    }

    /**
     * 事务操作 - 如果方法A在事务中被调用,并且方法A调用了方法B,则方法B将在一个嵌套事务中执行。嵌套事务是外部事务的一部分,可以独立提交或回滚,但只有当外部事务成功提交时,嵌套事务才会被提交。
     * 现象 - RbUser正常创建,RbOrder数据回滚
     *
     * @return void
     * @Author 俞春旺
     * @Date 上午 11:48:14 2023年6月19日 0019
     **/
    @Transactional(rollbackFor = Exception.class)
    public void transactional7() {
        // 构建 - 事务保存对象
        RbUser transactional7 = this.convertUser("transactional7");
        // 操作 - 保存用户数据
        boolean save = rbUserService.save(transactional7);
        Assert.isTrue(save, "保存失败");

        // 操作 - 新增订单数据,方法带入:@Transactional(rollbackFor = Exception.class)
        SpringUtil.getBean(TransactionalBizService.class).saveOrderTransactionalNested();
        // 代码模拟操作失败
        Assert.isTrue(false, "数据报错");
    }

    /**
     * 事务操作 - 如果方法A在事务中被调用,并且方法A调用了方法B,则方法B将在一个嵌套事务中执行。嵌套事务是外部事务的一部分,可以独立提交或回滚,但只有当外部事务成功提交时,嵌套事务才会被提交。
     * 现象 - RbUser正常创建,RbOrder数据回滚
     *
     * @return void
     * @Author 俞春旺
     * @Date 上午 11:48:14 2023年6月19日 0019
     **/
    public void transactional7_1() {
        // 构建 - 事务保存对象
        RbUser transactional7_1 = this.convertUser("transactional7_1");
        // 操作 - 保存用户数据
        boolean save = rbUserService.save(transactional7_1);
        Assert.isTrue(save, "保存失败");

        // 操作 - 新增订单数据,方法带入:@Transactional(rollbackFor = Exception.class)
        SpringUtil.getBean(TransactionalBizService.class).saveOrderTransactionalNested();
        // 代码模拟操作失败
        Assert.isTrue(false, "数据报错");
    }

    /**
     * 转换 - 用户信息
     *
     * @param name 用户名称
     * @return com.rbgt.tr.entity.UserTest
     * @Author 俞春旺
     * @Date 下午 01:43:15 2023年6月19日 0019
     **/
    private RbUser convertUser(String name) {
        RbUser user = new RbUser();
        user.setName(name);
        user.setPassword(3306);
        return user;
    }

    /**
     * 操作 - 新增订单数据
     *
     * @param
     * @return void
     * @Author 俞春旺
     * @Date 下午 01:42:22 2023年6月19日 0019
     **/
    @Transactional(rollbackFor = Exception.class)
    public void saveOrderTransactionalRequired() {
        // 构建 - 订单数据
        RbOrder rbOrder = this.convertOrder("saveOrderTransactionalRequired", "REQUIRED");
        // 操作 - 数据逻辑
        boolean save = rbOrderService.save(rbOrder);
        Assert.isTrue(save, "新增失败");
    }

    /**
     * 操作 - 新增订单数据
     * 无论方法A是否在事务中被调用,方法B都会创建一个新的事务,并在方法B执行完毕后提交该事务。如果方法A已经存在事务,那么方法A的事务将被挂起,直到方法B的事务完成
     *
     * @param
     * @return void
     * @Author 俞春旺
     * @Date 下午 01:42:22 2023年6月19日 0019
     **/
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void saveOrderTransactionalRequiredNew() {
        // 构建 - 订单数据
        RbOrder rbOrder = this.convertOrder("saveOrderTransactionalRequiredNew", "REQUIRES_NEW");
        // 操作 - 数据逻辑
        boolean save = rbOrderService.save(rbOrder);
        Assert.isTrue(save, "新增失败");
    }

    /**
     * 操作 - 新增订单数据
     * 如果方法A在事务中被调用,则方法B将加入到同一个事务中。如果方法A没有事务上下文,则方法B将以非事务方式执行。
     *
     * @param
     * @return void
     * @Author 俞春旺
     * @Date 下午 01:42:22 2023年6月19日 0019
     **/
    @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
    public void saveOrderTransactionalSupports() {
        // 构建 - 订单数据
        RbOrder rbOrder = this.convertOrder("saveOrderTransactionalSupports", "SUPPORTS");
        // 操作 - 数据逻辑
        boolean save = rbOrderService.save(rbOrder);
        Assert.isTrue(save, "新增失败");

        // 代码模拟操作失败
        Assert.isTrue(false, "数据报错");
    }

    /**
     * 操作 - 新增订单数据
     * 方法B将以非事务方式执行,即使方法A在事务中被调用。
     *
     * @param
     * @return void
     * @Author 俞春旺
     * @Date 下午 01:42:22 2023年6月19日 0019
     **/
    @Transactional(propagation = Propagation.NOT_SUPPORTED, rollbackFor = Exception.class)
    public void saveOrderTransactionalNotSupports() {
        // 构建 - 订单数据
        RbOrder rbOrder = this.convertOrder("saveOrderTransactionalNotSupports", "NOT_SUPPORTED");
        // 操作 - 数据逻辑
        boolean save = rbOrderService.save(rbOrder);
        Assert.isTrue(save, "新增失败");
    }

    /**
     * 操作 - 新增订单数据
     * 如果方法A在事务中被调用,则方法B将加入到同一个事务中。如果方法A没有事务上下文,则会抛出异常。
     *
     * @param
     * @return void
     * @Author 俞春旺
     * @Date 下午 01:42:22 2023年6月19日 0019
     **/
    @Transactional(propagation = Propagation.MANDATORY, rollbackFor = Exception.class)
    public void saveOrderTransactionalMandatory() {
        // 构建 - 订单数据
        RbOrder rbOrder = this.convertOrder("saveOrderTransactionalMandatory", "MANDATORY");
        // 操作 - 数据逻辑
        boolean save = rbOrderService.save(rbOrder);
        Assert.isTrue(save, "新增失败");
    }

    /**
     * 操作 - 新增订单数据
     * 如果方法A在事务中被调用,并且方法A调用了方法B,则方法B将在一个嵌套事务中执行。嵌套事务是外部事务的一部分,可以独立提交或回滚,但只有当外部事务成功提交时,嵌套事务才会被提交。
     *
     * @param
     * @return void
     * @Author 俞春旺
     * @Date 下午 01:42:22 2023年6月19日 0019
     **/
    @Transactional(propagation = Propagation.NEVER, rollbackFor = Exception.class)
    public void saveOrderTransactionalNever() {
        // 构建 - 订单数据
        RbOrder rbOrder = this.convertOrder("saveOrderTransactionalNever", "NEVER");
        // 操作 - 数据逻辑
        boolean save = rbOrderService.save(rbOrder);
        Assert.isTrue(save, "新增失败");
    }

    /**
     * 操作 - 新增订单数据
     * 如果方法A在事务中被调用,则会抛出异常。
     *
     * @param
     * @return void
     * @Author 俞春旺
     * @Date 下午 01:42:22 2023年6月19日 0019
     **/
    @Transactional(propagation = Propagation.NESTED, rollbackFor = Exception.class)
    public void saveOrderTransactionalNested() {
        // 构建 - 订单数据
        RbOrder rbOrder = this.convertOrder("saveOrderTransactionalNested", "NESTED");
        // 操作 - 数据逻辑
        boolean save = rbOrderService.save(rbOrder);
        Assert.isTrue(save, "新增失败");
    }


    /**
     * 转换 - 订单数据
     *
     * @param orderName 订单名称
     * @return com.rbgt.tr.entity.RbgtTestOrder
     * @Author 俞春旺
     * @Date 下午 01:41:00 2023年6月19日 0019
     **/
    private RbOrder convertOrder(String orderName, String trIntroduce) {
        RbOrder rbOrder = new RbOrder();
        rbOrder.setOrderName(orderName);
        rbOrder.setOrderPrice("3000");
        rbOrder.setTrIntroduce(trIntroduce);
        return rbOrder;
    }
}

(7)对应controller文件

@RestController
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class TransactionalController {

    private final TransactionalBizService transactionalBizService;

    @PutMapping("/transactional1")
    public String transactional1() {
        transactionalBizService.transactional1();
        return "transactional1方法执行完成";
    }

    @PutMapping("/transactional2")
    public String transactional2() {
        transactionalBizService.transactional2();
        return "transactional2方法执行完成";
    }

    @PutMapping("/transactional3")
    public String transactional3() {
        transactionalBizService.transactional3();
        return "transactional3方法执行完成";
    }

    @PutMapping("/transactional3_1")
    public String transactional3_1() {
        transactionalBizService.transactional3_1();
        return "transactional3_1方法执行完成";
    }

    @PutMapping("/transactional4")
    public String transactional4() {
        transactionalBizService.transactional4();
        return "transactional4方法执行完成";
    }

    @PutMapping("/transactional5")
    public String transactional5() {
        transactionalBizService.transactional5();
        return "transactional5方法执行完成";
    }

    @PutMapping("/transactional5_1")
    public String transactional5_1() {
        transactionalBizService.transactional5_1();
        return "transactional5_1方法执行完成";
    }

    @PutMapping("/transactional6")
    public String transactional6() {
        transactionalBizService.transactional6();
        return "transactional6方法执行完成";
    }

    @PutMapping("/transactional7")
    public String transactional7() {
        transactionalBizService.transactional7();
        return "transactional7方法执行完成";
    }

    @PutMapping("/transactional7_1")
    public String transactional7_1() {
        transactionalBizService.transactional7_1();
        return "transactional7方法执行完成";
    }
}

(8)对应pom依赖



    4.0.0

    
    
        org.springframework.boot
        SpringBoot
        1.0.0-SNAPSHOT
    

    org.springframework.boot
    SpringBoot-Transactional
    1.0.0-SNAPSHOT

    
        8
        8
    

    
        
            org.springframework.boot
            spring-boot-starter
        
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            com.alibaba
            druid-spring-boot-starter
            1.1.10
        
        
            mysql
            mysql-connector-java
        
        
        
            com.alibaba
            druid
            1.1.0
        
        
        
            com.baomidou
            mybatis-plus-boot-starter
            3.5.1
        

        
        
            com.google.guava
            guava
            28.2-jre
        

        
        
            org.springframework.boot
            spring-boot-starter-data-redis
        
        
            org.springframework
            spring-test
        

    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    

(9)对应yml文件

server:
  port: 10100   #  配置启动端口号

mybatis:
  config-location: classpath:mybatis.cfg.xml    #  mybatis主配置文件所在路径
  type-aliases-package: com.rbgt.tr.entity  #  定义所有操作类的别名所在包
  mapper-locations: #  所有的mapper映射文件
    - classpath:mapper/*.xml


spring: #springboot的配置
  datasource: #定义数据源
    #127.0.0.1为本机测试的ip,3306是mysql的端口号。serverTimezone是定义时区,照抄就好,mysql高版本需要定义这些东西
    #useSSL也是某些高版本mysql需要问有没有用SSL连接
    url: jdbc:mysql://127.0.0.1:3306/rbgt?serverTimezone=GMT%2B8&useSSL=FALSE
    username: root  #数据库用户名,root为管理员
    password: 123456 #该数据库用户的密码
    # 使用druid数据源
    type: com.alibaba.druid.pool.DruidDataSource
  redis:
    host: 127.0.0.1
    port: 6379
    timeout: 10000
    database: 5
    password: yiautos123456

# mybatis-plus相关配置
mybatis-plus:
  # xml扫描,多个目录用逗号或者分号分隔(告诉 Mapper 所对应的 XML 文件位置)
  mapper-locations: classpath:mapper/*.xml
  # 以下配置均有默认值,可以不设置
  global-config:
    # 配置逻辑删除全局值(1 表示已删除,0 表示未删除)
    logic-delete-value: 1
    logic-not-delete-value: 0
    db-config:
      #主键类型 AUTO:"数据库ID自增" INPUT:"用户输入ID",ID_WORKER:"全局唯一ID (数字类型唯一ID)", UUID:"全局唯一ID UUID";
      id-type: auto
      #字段策略 IGNORED:"忽略判断"  NOT_NULL:"非 NULL 判断")  NOT_EMPTY:"非空判断"
      field-strategy: NOT_EMPTY
      #数据库类型
      db-type: MYSQL
  configuration:
    configuration:
      # 分页插件
      # 需要配合pagehelper使用
      page-helper:
        helper-dialect: mysql
        reasonable: true
    # 是否开启自动驼峰命名规则映射:从数据库列名到Java属性驼峰命名的类似映射
    map-underscore-to-camel-case: true
    # 如果查询结果中包含空值的列,则 MyBatis 在映射的时候,不会映射这个字段
    call-setters-on-nulls: true
    # 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

(10)对应项目截图

@Transactional事务注解的传播性_第1张图片

3、最后补充@Transactional失效原因

  1. 错误配置事务管理器:事务管理器负责管理事务的创建、提交和回滚。如果事务管理器配置错误或未配置,那么事务将不会生效。确保正确配置了适合的事务管理器,例如Spring中的DataSourceTransactionManager。

  2. 不是公共方法或在同一类内部调用:@Transactional注解通常应用于公共方法上,以便可以被外部调用触发事务。如果将@Transactional注解应用于非公共方法,或者在同一个类内部的方法之间相互调用,事务可能不会生效。确保@Transactional注解应用于公共方法,并通过外部调用触发事务。

  3. 异常被捕获而不是抛出:默认情况下,只有在方法中抛出未捕获的RuntimeException或Error时,事务才会回滚。如果在方法内部捕获了异常并处理了它,事务将继续提交。确保在需要事务回滚的地方适当抛出RuntimeException或Error。

  4. 事务方法被同一个类中的其他方法调用:默认情况下,事务是通过AOP切面来实现的。如果在同一个类中的一个方法调用另一个带有@Transactional注解的方法,事务可能不会生效。这是因为AOP切面是通过代理来实现的,代理对象无法截获同一个类内部方法的调用。为了解决这个问题,可以通过将注解添加到另一个类中的方法来实现事务传播。

 PS:大家少走弯路,走大道,哈哈哈

你可能感兴趣的:(SpringBoot专题,数学建模,java,python)