事务的传播特性之@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:如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务。