事务的传播特性之@Transactional使用详解

事务的传播特性之@Transactional使用详解

一、@Transactional

事务的传播特性有如下7个:

public enum Propagation {
    REQUIRED(0),
    SUPPORTS(1),
    MANDATORY(2),
    REQUIRES_NEW(3),
    NOT_SUPPORTED(4),
    NEVER(5),
    NESTED(6);

    private final int value;

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

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

@Transactional注解默认使用事务传播特性是REQUIRED

Propagation propagation() default Propagation.REQUIRED;

二、编码详解

1.准备基础代码

定义如下接口及其相应实现

    public void test1();

    public void test2();
	@Override
    public void test1() {
        User user= new User();
        user.setName("test1");
        user.setAge(19);
        userMapper.insert(user);
    }

    @Override
    public void test2() {
        test3();
        int number = 1 / 0;
        test4();
    }

    public void test3(){
        User user= new User();
        user.setName("test3");
        user.setAge(22);
        userMapper.insert(user);
    }

    public void test4(){
        User user= new User();
        user.setName("test4");
        user.setAge(22);
        userMapper.insert(user);
    }
public interface TestTransService {
    public void test();
}
@Service
public class TestTransServiceImpl implements TestTransService {

    @Autowired
    private UserService userService;
    
    @Override
    public void test(){
        userService.test1();
        userService.test2();
    }
}

集成测试

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class TransTest {
    
    @Autowired
    private TestTransService testTransService;

    @Test
    public void test() {
        testTransService.test();
    }
}

2.REQUIRED

Test1

不添加事务注解,直接运行上述代码,没有使用到事务,test1()与test3()执行了。

Test2

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void test() {
        this.test1();
        this.test2();
    }
test()及其子方法事务生效

结论:

如果当前存在事务,则其他方法则加入这个事务,成为一个整体。

Test3

    @Override
    public void test() {
        this.test1();
        this.test2();
    }
    
  @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void test2() {
        test3();
        int number = 1 / 0;
        test4();
    }
test1()方法事务未生效,test2()方法事务生效

结论:

如果当前方法没有事务,若子方法有事务注解标识,则新建一个事务,并且该子方法运行在该事务中。

Test4

 @Transactional(propagation = Propagation.REQUIRED)
 @Override
    public void test() {
        this.test1();
        this.test2();
        int number = 1 / 0;
    }

 @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void test2() {
        test3();
       // int number = 1 / 0;
        test4();
    }

结论:

当前方法存在事务,则加入这个事务,使用同一个事务,所有方法事务回滚。

3.SUPPORTS

Test1

  @Override
    public void test(){
        stuService.test1();
        stuService.test2();
    }

    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public void test2() {
        test3();
        int number = 1 / 0;
        test4();
    }
test1()与test3()方法事务未生效

结论:

如果当前没有事务,则不使用事务。

Test2

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void test() {
        this.test1();
        this.test2();
    }

    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public void test2() {
        test3();
        int number = 1 / 0;
        test4();
    }
事务都生效了

结论:

如果当前有事务,则使用事务

4.MANDATORY

Test1

 @Override
    public void test() {
        this.test1();
        this.test2();
    }

 @Transactional(propagation = Propagation.MANDATORY)
    @Override
    public void test2() {
        test3();
        int number = 1 / 0;
        test4();
    }

test1()事务未生效,test2()抛出异常:

org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'

Test2

 @Transactional(propagation = Propagation.REQUIRED)
 @Override
    public void test() {
        this.test1();
        this.test2();
    }

 @Transactional(propagation = Propagation.MANDATORY)
    @Override
    public void test2() {
        test3();
        int number = 1 / 0;
        test4();
    }
所有方法事务生效

结论:

该传播属性强制必须存在一个事务,如果不存在,则抛出异常

5.REQUIRES_NEW

Test1

 @Override
    public void test() {
        this.test1();
        this.test2();
    }

 @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public void test2() {
        test3();
        int number = 1 / 0;
        test4();
    }
test1()方法事务未生效,test2()方法事务生效。

结论:

如果当前没有事务,则自己新建一个事务,并运行在该事务中

Test2

 @Transactional(propagation = Propagation.REQUIRED)
 @Override
    public void test() {
        this.test1();
        this.test2();
    }

 @Transactional(propagation = Propagation.MANDATORY)
    @Override
    public void test2() {
        test3();
        int number = 1 / 0;
        test4();
    }
test2()方法事务回滚,影响到test()方法事务触发,导致test()1方法事务生效

结论:

如果当前有事务,则挂起该事务,并且自己创建一个新的事务给自己使用;

Test3

 @Transactional(propagation = Propagation.REQUIRED)
 @Override
    public void test() {
        this.test1();
        this.test2();
        int number = 1 / 0;
    }

 @Transactional(propagation = Propagation.MANDATORY)
    @Override
    public void test2() {
        test3();
       // int number = 1 / 0;
        test4();
    }
test1()方法事务回滚,test2()方法正常执行。

6.NOT_SUPPORTED

Test1

 @Override
    public void test() {
        this.test1();
        this.test2();
    }

 @Transactional(propagation = Propagation.NOT_SUPPORTED)
    @Override
    public void test2() {
        test3();
        int number = 1 / 0;
        test4();
    }
所有方法都没有事务。

Test2

 @Transactional(propagation = Propagation.REQUIRED)
 @Override
    public void test() {
        this.test1();
        this.test2();
    }

 @Transactional(propagation = Propagation.NOT_SUPPORTED)
    @Override
    public void test2() {
        test3();
        int number = 1 / 0;
        test4();
    }
test1()方法事务生效,test2()方法事务未生效。

结论:

如果当前有事务,则把事务挂起,自己不使用该事务。

7.NEVER

Test1

 @Override
    public void test() {
        this.test1();
        this.test2();
    }

 @Transactional(propagation = Propagation.NEVER)
    @Override
    public void test2() {
        test3();
        int number = 1 / 0;
        test4();
    }
test1()方法与test2()方法事务未生效。

Test2

 @Transactional(propagation = Propagation.REQUIRED)
 @Override
    public void test() {
        this.test1();
        this.test2();
    }

 @Transactional(propagation = Propagation.NEVER)
    @Override
    public void test2() {
        test3();
        int number = 1 / 0;
        test4();
    }

test1()方法事务生效,test2()方法抛出异常:

org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation 'never'

结论:

如果当前有事务存在,则抛出异常。

8.NESTED

Test1

 @Override
    public void test() {
        this.test1();
        this.test2();
    }

 @Transactional(propagation = Propagation.NESTED)
    @Override
    public void test2() {
        test3();
        int number = 1 / 0;
        test4();
    }
test()方法事务未回滚,结论:如果当前没有事务,则自己新建一个事务

Test2

 @Transactional(propagation = Propagation.REQUIRED)
 @Override
    public void test() {
        this.test1();
        this.test2();
    }

 @Transactional(propagation = Propagation.NESTED)
    @Override
    public void test2() {
        test3();
        int number = 1 / 0;
        test4();
    }

结论:

如果当前有事务,则开启子事务(嵌套事务),嵌套事务是独立提交或者回滚;

Test3

 @Transactional(propagation = Propagation.REQUIRED)
 @Override
    public void test() {
        this.test1();
        this.test2();
        int number = 1 / 0;
    }

 @Transactional(propagation = Propagation.NESTED)
    @Override
    public void test2() {
        test3();
       // int number = 1 / 0;
        test4();
    }

结论:

主事务提交,则会携带子事务一起提交,如果主事务回滚,则子事务会一起回滚。

Test4

 @Transactional(propagation = Propagation.REQUIRED)
 @Override
    public void test() {
        this.test1();
        this.test2();
    }

 @Transactional(propagation = Propagation.NESTED)
    @Override
    public void test2() {
        test3();
        int number = 1 / 0;
        test4();
    }
子事务出现异常,影响到主事务,事务回滚
 @Transactional(propagation = Propagation.REQUIRED)
 @Override
    public void test() {
        this.test1();
       try {
            stuService.test2();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

 @Transactional(propagation = Propagation.NESTED)
    @Override
    public void test2() {
        test3();
        int number = 1 / 0;
        test4();
    }
子事务出现异常,处理该子事务异常,test1()成功执行(事务不回滚),test2()事务回滚

结论:

子事务异常,则父事务可以回滚或不回滚。

三、总结

REQUIRED:如果当前没有事务,就新建一个事务。如果当前存在事务,则加入这个事务。这是最常见的选择。 

SUPPORTS:如果当前没有事务,就以非事务方式执行。 如果当前有事务,则使用事务。

MANDATORY:如果当前没有事务,就抛出异常。 

REQUIRES_NEW:如果当前存在事务,把当前事务挂起,并且自己创建一个新的事务给自己使用。如果当前没有事务,则自己新建一个事务。 

NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 

NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。 

NESTED:如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务。
上一篇:新老手必备的34种JavaScript简写优化技术


下一篇:Java中的String类