Spring事务相关注解介绍

@EnableTransactionManagement

@EnableTransactionManagement 是 Spring 提供的一个注解,用于开启 Spring 的事务管理功能。当我们在 Spring 项目中使用了事务操作时,需要在 Spring 配置文件中进行配置,包括数据源、事务管理器等。使用 @EnableTransactionManagement 注解后,Spring 会扫描容器中所有带有 @Transactional 注解的方法,自动为其添加事务管理。这样我们就不需要在每个事务方法上手动编写事务管理代码,提高了开发效率和代码质量。

使用@EnableTransactionManagement注解后,Spring会自动创建一个名为transactionManager的事务管理器,并且会自动在需要事务管理的方法(被@Transactional注解的方法)上添加事务拦截器,以便在方法执行时开启、提交、回滚事务等操作。此外,我们还可以通过在方法上使用@Transactional注解,来指定事务的属性,比如事务的传播行为、隔离级别、超时时间等等。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({TransactionManagementConfigurationSelector.class})
public @interface EnableTransactionManagement {
    boolean proxyTargetClass() default false;

    AdviceMode mode() default AdviceMode.PROXY;

    int order() default Integer.MAX_VALUE;
}

@Transactional

@Transactional注解用于控制事务的属性。通过在方法或类上添加@Transactional注解,可以指定事务管理器应该如何处理这个方法或类中的事务。

@Transactional注解可以用于以下几种情况:

  1. 在方法上使用:通过将@Transactional注解添加到方法上,可以指示Spring在事务管理下执行该方法。如果在方法中发生错误,Spring将回滚事务以确保数据的完整性。
  2. 在类上使用:当@Transactional注解添加到类上时,它会将所有公共方法都配置为支持事务。
  3. 在接口上使用:在接口上使用@Transactional注解是将它们的所有实现方法都视为受事务管理器控制的事务的一部分。

除了使用@Transactional注解来控制事务属性之外,还可以使用编程式事务管理,这需要在代码中显式地启动、提交或回滚事务。但使用@Transactional注解能够更方便地控制事务,因为它可以在更高的层次上管理事务,而不需要在业务逻辑中嵌入事务管理代码。

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
    @AliasFor("transactionManager")
    String value() default "";

    @AliasFor("value")
    String transactionManager() default "";

    String[] label() default {};

    Propagation propagation() default Propagation.REQUIRED;

    Isolation isolation() default Isolation.DEFAULT;

    int timeout() default -1;

    String timeoutString() default "";

    boolean readOnly() default false;

    Class<? extends Throwable>[] rollbackFor() default {};

    String[] rollbackForClassName() default {};

    Class<? extends Throwable>[] noRollbackFor() default {};

    String[] noRollbackForClassName() default {};
}

// 事务传播隔离级别
public enum Propagation {
    REQUIRED(0),// 默认的事务隔离级别,如果当前没有事务,则创建一个事务,如果存在事务了,则加入当前事务并在方法结束时一起提交。
    SUPPORTS(1),// 如果当前存在事务,则加入该事务;否则不使用事务。适用于只需要读取数据而不更新数据的方法。	
    MANDATORY(2),// 必须在当前事务中执行。如果当前没有事务,则抛出异常。
    REQUIRES_NEW(3),// 创建一个新的事务,如果已经存在事务,则挂起当前事务。在方法结束时,提交新的事务并恢复旧事务。考虑锁的问题。新事务的回滚不会影响外部事务
    NOT_SUPPORTED(4),// 不在事务中执行。如果当前存在事务,则挂起事务并在方法执行完毕后恢复它。没有事务,执行修改失败不会进行异常回滚
    NEVER(5),// 不在事务中执行。如果当前存在事务,则抛出异常。
    NESTED(6);// 如果当前存在事务,则在嵌套的事务中执行。在方法结束时,只提交嵌套的事务,并将其合并到外部事务中。如果没有外部事务,则相当于REQUIRED传播级别。

    private final int value;

    private Propagation(int value) {
        this.value = value;
    }

    public int value() {
        return this.value;
    }
}

REQUIRED

@Transactional(propagation=Propagation.REQUIRED,rollbackFor = NullPointerException.class)
public void B(){
    throw new NullPointerException();
}
@Transactional
pubic void A(){
    try{
		B();
	}catch (NullPointerException e){
		System.out.println("test: " + e);
	}
    // 方法A在开启事务的情况下调用方法B,如果捕获了方法B的异常并没有抛出,此时出现
    org.springframework.transaction.UnexpectedRollbackException: 
    Transaction rolled back because it has been marked as rollback-only
    原因是方法B的事务已经加入的方法中,该事务的提交和回滚操作应该由方法A来决定,
    但是在B发生了异常,由于方法B发生NullPointerException,所有要回滚事务,出现冲突。
    
}

pubic void A(){
    try{
		B();
	}catch (NullPointerException e){
		System.out.println("test: " + e);
	}
    // 方法A在没有添加@Transaction事务的情况下调用方法B,不管有没有捕获异常,方法B的事务都会回滚
    只要方法A执行数据库写的操作在B调用之前,数据会插入到数据库,不会回滚
    
}

MANDATORY 必须在当前事务中执行。如果当前没有事务,则抛出异常。

执行@Transactional(propagation=Propagation.MANDATORY)为这个隔离级别,如果执行注解的方法中没有事务,则报错org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation ‘mandatory’

@Test
void testTransaction(){
        ClassModel classModel = new ClassModel();
        String id = UUID.randomUUID().toString().replaceAll("-","");
        classModel.setId(id);
        classModel.setGrade("1");
        classModel.setName(id.substring(0,4));

        System.out.println(classService.saveClass(classModel));
}

@Override
//@Transactional(propagation = Propagation.REQUIRED)
public boolean saveClass(ClassModel classModel) {

        log.info("class save:" + gson.toJson(classModel));
        // 创建班级对象
        classMapper.saveClass(classModel);
        StudentModel studentModel = new StudentModel();
        String id = UUID.randomUUID().toString().replaceAll("-","");
        studentModel.setId(id);
        studentModel.setSex("0");
        studentModel.setAge(18);
        studentModel.setName(id.substring(30) + "-" +classModel.getName().substring(0,4));

        log.info("student save:" + gson.toJson(studentModel));
        boolean flag = studentService.saveStudent(studentModel);
        
        return true;
}

@Override
@Transactional(propagation = Propagation.MANDATORY)
public boolean saveStudent(StudentModel studentModel) {
        int result = studentMapper.saveStudent(studentModel);
        return true;
}
// 如果注释掉saveClass方法上面的事务,则出现
org.springframework.transaction.IllegalTransactionStateException: 
No existing transaction found for transaction marked with propagation 'mandatory'异常
因为这个事务传播隔离级别只能在事务中使用,注释掉这个注解,这个方法就没有事务了,只有你手动开启一个事务才不会报错。

NESTED 不在事务中执行。如果当前存在事务,则抛出异常

Spring事务传播隔离级别NESTED表示在一个已经存在的事务中开启一个新的事务。它与REQUIRED传播级别相似,不同之处在于NESTED事务可以被嵌套在外层事务之中,形成一个事务的嵌套结构。当NESTED事务中的操作失败时,只会回滚NESTED事务中的操作,而不会回滚外层事务中的操作。

ESTED事务的提交和回滚行为受外层事务的影响。如果外层事务成功提交,那么内层事务也会被提交;如果外层事务回滚,那么内层事务也会被回滚。同时,NESTED事务也支持保存点操作,可以在嵌套事务内部设置保存点,然后进行部分回滚操作。

需要注意的是,NESTED事务只能在支持保存点的事务管理器上使用,比如Spring的JtaTransactionManager和DataSourceTransactionManager。如果使用不支持保存点的事务管理器,NESTED事务就会退化为REQUIRED事务。

思考手动回滚事务

在下面的代码中数据库会有新增记录吗?

@Test
void testTransaction(){
        ClassModel classModel = new ClassModel();
        String id = UUID.randomUUID().toString().replaceAll("-","");
        classModel.setId(id);
        classModel.setGrade("1");
        classModel.setName(id.substring(0,4));

        System.out.println(classService.saveClass(classModel));
}

@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public boolean saveClass(ClassModel classModel) {

        log.info("class save:" + gson.toJson(classModel));
        // 创建班级对象
        classMapper.saveClass(classModel);
        StudentModel studentModel = new StudentModel();
        String id = UUID.randomUUID().toString().replaceAll("-","");
        studentModel.setId(id);
        studentModel.setSex("0");
        studentModel.setAge(18);
        studentModel.setName(id.substring(30) + "-" +classModel.getName().substring(0,4));

        log.info("student save:" + gson.toJson(studentModel));
        boolean flag = false;

        flag = studentService.saveStudent(studentModel);


        if (!flag){
        	// 手动回滚事务
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return false;
        }

        return true;
}

@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
    public boolean saveStudent(StudentModel studentModel) {
        int result = studentMapper.saveStudent(studentModel);
        return false;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值