简单来说就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行。比如事务方法A()调用事务方法B()时,事务方法B()是继续在A()的事务中运行还是单独新建使用自个的事务B,这就取决于事务方法B()的事务传播行为
//service1
@Transactional(propagation = Propagation.REQUIRED)
public void B() {}
//service2
@Transactional(propagation = Propagation.REQUIRED)
public void A() {
B()
}
A() 和 B()方法都开启了事务,而A()方法调用了B()。
spring提供的七种事务传播行为
- REQUIRED:表示当前方法必须运行在事务中,如果当前方法没有运行在事务中,就新建一个事务,如果当前方法已存在于一个事务中,就加入到这个事务中,在该事务中运行
- SUPPORTS:表示当前方法是否已经存在于一个事务,如果当前方法已经在一个事务中,就加入该事务,否则就以非事务方法执行,相当于普通方法。
- MANDATORY:表示当前方法必须运行在一个事务中,如果没有在一个事务中会抛出异常。IllegalTransactionStateException:No existing transaction found for transaction marked with propagation 'mandatory'
- REQUIRES_NEW:表示当前方法必须运行在自己的事务中,如果已经存于一个事务中,则挂起该事务,重新开启一个属于自己的事务。也就是当前方法的事务不受其他事务影响
- NOT_SUPPORTED:表示当前方法不在事务中运行,如果已经存在于一个事务中,则将该事务挂起,否则则视为普通非事务方法运行。
- NEVER:表示当前方法不在事务中运行,如果已经存在于一个事务中,则抛出一个异常,否则则视为普通非事务方法运行
- NESTED:表示当前方法已经运行在一个事务中,则在嵌套在事务内执行,嵌套事务可以单独的提交和回滚,但是如果主事务提交或回滚,会顺带着嵌套事务提交或回滚,嵌套事务出现异常,主事务可以有选择的回滚或不回滚,可以在主事务方法中catch子方法的异常,catch后其他方法就不会受到影响。如果当前没有事务,则执行与REQUIRED类似的操作
以上说法可能并不能很好的理解下面我们通过伪代码演示一下每个行为
一、验证Propagation.REQUIRED
1.子方法添加事务并使用REQUIRED,父方法不添加事务
@Service
public class StuServiceImpl implements IStuService {
@Autowired
private StuMapper stuMapper;
@Override
public void saveParent() {
Stu stu = new Stu();
stu.setName("parent");
stu.setAge(19);
stuMapper.insert(stu);
}
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void saveChildren() {
saveChild1();
int a = 1 / 0;
saveChild2();
}
public void saveChild1() {
Stu stu1 = new Stu();
stu1.setName("child-1");
stu1.setAge(11);
stuMapper.insert(stu1);
}
public void saveChild2() {
Stu stu2 = new Stu();
stu2.setName("child-2");
stu2.setAge(22);
stuMapper.insert(stu2);
}
}
******************************************************************************
@Service
public class TestServiceImpl implements ITestService {
//注入上面的service
@Autowired
private IStuService iStuService;
@Override
public void testTrans() {
iStuService.saveParent();
iStuService.saveChildren();
}
}
.........
调用testTrans();
运行结果为:
我们发现只有parent被插入到数据库中,而两个children则没有,这是因为在saveChildren()方法中发生了 / by zero 异常,所以会进行事务回滚,已经插入的children1被清除。
子方法被父方法调用,父方法没有事务,因而子方法没有运行在事务中,所以子方法新建一个事务并运行
2.子方法不添加事务,父方法添加事务并使用REQUIRED
@Service
public class StuServiceImpl implements IStuService {
@Autowired
private StuMapper stuMapper;
@Override
public void saveParent() {
Stu stu = new Stu();
stu.setName("parent");
stu.setAge(19);
stuMapper.insert(stu);
}
@Override
public void saveChildren() {
saveChild1();
int a = 1 / 0;
saveChild2();
}
public void saveChild1() {
Stu stu1 = new Stu();
stu1.setName("child-1");
stu1.setAge(11);
stuMapper.insert(stu1);
}
public void saveChild2() {
Stu stu2 = new Stu();
stu2.setName("child-2");
stu2.setAge(22);
stuMapper.insert(stu2);
}
}
********************************************************************************
@Service
public class TestServiceImpl implements ITestService {
//注入上面的service
@Autowired
private IStuService iStuService;
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void testTrans() {
iStuService.saveParent();
iStuService.saveChildren();
}
}
.........
调用testTrans();
运行结果为:
我们发现数据库中一条记录也没有被添加,这是因为在子方法saveChildren()方法中发生了 / by zero 异常,子方法异常被父方法感知到,所以会进行全部回滚处理
3.子方法添加事务,父方法添加事务,都使用REQUIRED
@Service
public class StuServiceImpl implements IStuService {
@Autowired
private StuMapper stuMapper;
@Override
public void saveParent() {
Stu stu = new Stu();
stu.setName("parent");
stu.setAge(19);
stuMapper.insert(stu);
}
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void saveChildren() {
saveChild1();
int a = 1 / 0;
saveChild2();
}
public void saveChild1() {
Stu stu1 = new Stu();
stu1.setName("child-1");
stu1.setAge(11);
stuMapper.insert(stu1);
}
public void saveChild2() {
Stu stu2 = new Stu();
stu2.setName("child-2");
stu2.setAge(22);
stuMapper.insert(stu2);
}
}
********************************************************************************
@Service
public class TestServiceImpl implements ITestService {
//注入上面的service
@Autowired
private IStuService iStuService;
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void testTrans() {
iStuService.saveParent();
iStuService.saveChildren();
}
}
.........
调用testTrans();
运行结果:
结果也是一条记录都没有
对于子方法来说,当前已经存在一个父方法的事务,而且子方法被@Transactional(propagation = Propagation.REQUIRED) 修饰,所以子方法会加入到父方法的事务中
二、验证Propagation.SUPPORTS
1.子方法加入@Transactional(propagation = Propagation.SUPPORTS),父方法为普通方法
@Service
public class StuServiceImpl implements IStuService {
@Autowired
private StuMapper stuMapper;
@Override
public void saveParent() {
Stu stu = new Stu();
stu.setName("parent");
stu.setAge(19);
stuMapper.insert(stu);
}
@Override
@Transactional(propagation = Propagation.SUPPORTS)
public void saveChildren() {
saveChild1();
int a = 1 / 0;
saveChild2();
}
public void saveChild1() {
Stu stu1 = new Stu();
stu1.setName("child-1");
stu1.setAge(11);
stuMapper.insert(stu1);
}
public void saveChild2() {
Stu stu2 = new Stu();
stu2.setName("child-2");
stu2.setAge(22);
stuMapper.insert(stu2);
}
}
**********************************************************************************************
@Service
public class TestServiceImpl implements ITestService {
//注入上面的service
@Autowired
private IStuService iStuService;
@Override
public void testTrans() {
iStuService.saveParent();
iStuService.saveChildren();
}
}
.........
调用testTrans();
运行结果:
通过结果我们发现,虽然在子方法上加入@Transactional(propagation = Propagation.SUPPORTS) 但是结果却是跟非事务方法结果一致,下面我们在将父方法添加事务看下结果
@Service
public class StuServiceImpl implements IStuService {
@Autowired
private StuMapper stuMapper;
@Override
public void saveParent() {
Stu stu = new Stu();
stu.setName("parent");
stu.setAge(19);
stuMapper.insert(stu);
}
@Override
@Transactional(propagation = Propagation.SUPPORTS)
public void saveChildren() {
saveChild1();
int a = 1 / 0;
saveChild2();
}
public void saveChild1() {
Stu stu1 = new Stu();
stu1.setName("child-1");
stu1.setAge(11);
stuMapper.insert(stu1);
}
public void saveChild2() {
Stu stu2 = new Stu();
stu2.setName("child-2");
stu2.setAge(22);
stuMapper.insert(stu2);
}
}
**********************************************************************************************
@Service
public class TestServiceImpl implements ITestService {
//注入上面的service
@Autowired
private IStuService iStuService;
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void testTrans() {
iStuService.saveParent();
iStuService.saveChildren();
}
}
.........
调用testTrans();
我们在父方法上添加@Transactional(propagation = Propagation.REQUIRED) 子方法上加入 @Transactional(propagation = Propagation.SUPPORTS)
运行结果:
也就是说当父方法有事务时,子方法会加入到父方法的事务中,否则就按非事务方法也就是普通方法运行。
三、验证Propagation.MANDATORY
1.子方法添加@Transactional(propagation = Propagation.MANDATORY) ,父方法为普通方法
@Service
public class StuServiceImpl implements IStuService {
@Autowired
private StuMapper stuMapper;
@Override
public void saveParent() {
Stu stu = new Stu();
stu.setName("parent");
stu.setAge(19);
stuMapper.insert(stu);
}
@Override
@Transactional(propagation = Propagation.MANDATORY)
public void saveChildren() {
saveChild1();
int a = 1 / 0;
saveChild2();
}
public void saveChild1() {
Stu stu1 = new Stu();
stu1.setName("child-1");
stu1.setAge(11);
stuMapper.insert(stu1);
}
public void saveChild2() {
Stu stu2 = new Stu();
stu2.setName("child-2");
stu2.setAge(22);
stuMapper.insert(stu2);
}
}
**********************************************************************************************
@Service
public class TestServiceImpl implements ITestService {
//注入上面的service
@Autowired
private IStuService iStuService;
@Override
public void testTrans() {
iStuService.saveParent();
iStuService.saveChildren();
}
}
.........
调用testTrans();
运行结果:
子方法直接报错:
org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'
2.子方法添加@Transactional(propagation = Propagation.MANDATORY) ,父方法添加@Transactional(propagation = Propagation.REQUIRED)
@Service
public class StuServiceImpl implements IStuService {
@Autowired
private StuMapper stuMapper;
@Override
public void saveParent() {
Stu stu = new Stu();
stu.setName("parent");
stu.setAge(19);
stuMapper.insert(stu);
}
@Override
@Transactional(propagation = Propagation.MANDATORY)
public void saveChildren() {
saveChild1();
int a = 1 / 0;
saveChild2();
}
public void saveChild1() {
Stu stu1 = new Stu();
stu1.setName("child-1");
stu1.setAge(11);
stuMapper.insert(stu1);
}
public void saveChild2() {
Stu stu2 = new Stu();
stu2.setName("child-2");
stu2.setAge(22);
stuMapper.insert(stu2);
}
}
**********************************************************************************************
@Service
public class TestServiceImpl implements ITestService {
//注入上面的service
@Autowired
private IStuService iStuService;
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void testTrans() {
iStuService.saveParent();
iStuService.saveChildren();
}
}
.........
调用testTrans();
运行结果:
子方法加入到父方法的事务中,子方法异常,事务整体回滚
四、验证Propagation.REQUIRES_NEW
1. 子方法使用 @Transactional(propagation = Propagation.REQUIRES_NEW) 父方法为普通方法
@Service
public class StuServiceImpl implements IStuService {
@Autowired
private StuMapper stuMapper;
@Override
public void saveParent() {
Stu stu = new Stu();
stu.setName("parent");
stu.setAge(19);
stuMapper.insert(stu);
}
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveChildren() {
saveChild1();
int a = 1 / 0;
saveChild2();
}
public void saveChild1() {
Stu stu1 = new Stu();
stu1.setName("child-1");
stu1.setAge(11);
stuMapper.insert(stu1);
}
public void saveChild2() {
Stu stu2 = new Stu();
stu2.setName("child-2");
stu2.setAge(22);
stuMapper.insert(stu2);
}
}
**********************************************************************************************
@Service
public class TestServiceImpl implements ITestService {
//注入上面的service
@Autowired
private IStuService iStuService;
@Override
public void testTrans() {
iStuService.saveParent();
iStuService.saveChildren();
}
}
.........
调用testTrans();
运行结果:
仅在子方法中开启事务,子方法saveChildren()事务回滚
2. 子方法使用 @Transactional(propagation = Propagation.REQUIRES_NEW) 父方法使用 @Transactional(propagation = Propagation.REQUIRED)
@Service
public class StuServiceImpl implements IStuService {
@Autowired
private StuMapper stuMapper;
@Override
public void saveParent() {
Stu stu = new Stu();
stu.setName("parent");
stu.setAge(19);
stuMapper.insert(stu);
}
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveChildren() {
saveChild1();
int a = 1 / 0;
saveChild2();
}
public void saveChild1() {
Stu stu1 = new Stu();
stu1.setName("child-1");
stu1.setAge(11);
stuMapper.insert(stu1);
}
public void saveChild2() {
Stu stu2 = new Stu();
stu2.setName("child-2");
stu2.setAge(22);
stuMapper.insert(stu2);
}
}
**********************************************************************************************
@Service
public class TestServiceImpl implements ITestService {
//注入上面的service
@Autowired
private IStuService iStuService;
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void testTrans() {
iStuService.saveParent();
iStuService.saveChildren();
}
}
.........
调用testTrans();
运行结果:
子方法虽然单独运行一个事务,但是异常被父方法识别到,所以父方法事务进行了回滚
3.下面我们调整一下,将子方法中除0异常转移到父方法中,再看下结果
@Service
public class StuServiceImpl implements IStuService {
@Autowired
private StuMapper stuMapper;
@Override
public void saveParent() {
Stu stu = new Stu();
stu.setName("parent");
stu.setAge(19);
stuMapper.insert(stu);
}
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveChildren() {
saveChild1();
//int a = 1 / 0; 将这个异常语句注释掉添加到父方法中
saveChild2();
}
public void saveChild1() {
Stu stu1 = new Stu();
stu1.setName("child-1");
stu1.setAge(11);
stuMapper.insert(stu1);
}
public void saveChild2() {
Stu stu2 = new Stu();
stu2.setName("child-2");
stu2.setAge(22);
stuMapper.insert(stu2);
}
}
**********************************************************************************************
@Service
public class TestServiceImpl implements ITestService {
//注入上面的service
@Autowired
private IStuService iStuService;
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void testTrans() {
iStuService.saveParent();
iStuService.saveChildren();
int a = 1 / 0; //新增一个异常语句
}
}
.........
调用testTrans();
运行结果:
通过结果我们可以看到,父方法出现异常,但是仅仅回滚了saveParent()方法。而saveChildren()则正常保存到数据库中,没有发生回滚。
也就是说REQUIRES_NEW 是新启动一个事务,它所在的已经存在的那个事务会被挂起。
五、验证Propagation.NOT_SUPPORTED
1.子方法上加入@Transactional(propagation = Propagation.NOT_SUPPORTED),父方法为普通非事务方法
@Service
public class StuServiceImpl implements IStuService {
@Autowired
private StuMapper stuMapper;
@Override
public void saveParent() {
Stu stu = new Stu();
stu.setName("parent");
stu.setAge(19);
stuMapper.insert(stu);
}
@Override
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void saveChildren() {
saveChild1();
int a = 1 / 0;
saveChild2();
}
public void saveChild1() {
Stu stu1 = new Stu();
stu1.setName("child-1");
stu1.setAge(11);
stuMapper.insert(stu1);
}
public void saveChild2() {
Stu stu2 = new Stu();
stu2.setName("child-2");
stu2.setAge(22);
stuMapper.insert(stu2);
}
}
**********************************************************************************************
@Service
public class TestServiceImpl implements ITestService {
//注入上面的service
@Autowired
private IStuService iStuService;
@Override
public void testTrans() {
iStuService.saveParent();
iStuService.saveChildren();
}
}
.........
调用testTrans();
运行结果:
通过结果可以看出,该子方法以非事务方式运行
2.子方法上加入@Transactional(propagation = Propagation.NOT_SUPPORTED),父方法上加入 @Transactional(propagation = Propagation.REQUIRED)
@Service
public class StuServiceImpl implements IStuService {
@Autowired
private StuMapper stuMapper;
@Override
public void saveParent() {
Stu stu = new Stu();
stu.setName("parent");
stu.setAge(19);
stuMapper.insert(stu);
}
@Override
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void saveChildren() {
saveChild1();
int a = 1 / 0;
saveChild2();
}
public void saveChild1() {
Stu stu1 = new Stu();
stu1.setName("child-1");
stu1.setAge(11);
stuMapper.insert(stu1);
}
public void saveChild2() {
Stu stu2 = new Stu();
stu2.setName("child-2");
stu2.setAge(22);
stuMapper.insert(stu2);
}
}
**********************************************************************************************
@Service
public class TestServiceImpl implements ITestService {
//注入上面的service
@Autowired
private IStuService iStuService;
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void testTrans() {
iStuService.saveParent();
iStuService.saveChildren();
}
}
.........
调用testTrans();
运行结果:
从结果我们可以看出,该子方法以非事务方式运行,而该方法的异常被父方法识别到后父方法进行了回滚