今天看了一下spring中的几种事务传播,记录一下
源码
一共有7种:(默认:REQUIRED)
REQUIRED(0),
SUPPORTS(1),
MANDATORY(2),
REQUIRES_NEW(3),
NOT_SUPPORTED(4),
NEVER(5),
NESTED(6);
1.REQUIRED
如果方法在运行的时候存在事务,已经存在了一个事务,那么会加入到该事务中,否则的话自己创建一个新的事务。(spring的默认传播行为就是REQUIRED)
例子:
Food的方法里添加传播行为,User不添加,在调用两者方法的父级方法加上传播行为执行时,因为抛出了异常导致回滚,此时food和user两张表是没有数据入库的,因为food添加了REQUIRED传播行为没有将数据加入到数据库中,user就是加入到了父级的事务中,所以没有数据没有入库。
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void add(FoodEntity foodEntity) {
foodMapper.insert(foodEntity);
}
@Override
public void add(UsersEntity usersEntity) {
usersMapper.insert(usersEntity);
}
@Transactional(propagation = Propagation.REQUIRED)
@Test
public void contextLoads() {
FoodEntity foodEntity = new FoodEntity();
foodEntity.setName("apple");
foodService.add(foodEntity)
UsersEntity usersEntity = new UsersEntity();
usersEntity.setName("小明");
usersService.add(usersEntity);
log.info("value={}", 1 / 0);
}
2.SUPPORTS
如果有事务就在事务的环境下执行,否则反之不在事务的环境下执行。
例子:
如果testSupports方法不加@Transactional(propagation = Propagation.REQUIRED)事务执行,那么addS方法就会将数据存入数据库中;如果加了事务那么就不会将数据存入数据库,因为抛出了异常事务回滚。
@Transactional(propagation = Propagation.SUPPORTS)
@Override
public void addS(UsersEntity usersEntity) {
usersMapper.insert(usersEntity);
}
@Transactional(propagation = Propagation.REQUIRED)
@Test
public void testSupports() {
UsersEntity usersEntity = new UsersEntity();
usersEntity.setName("小明");
usersService.addS(usersEntity);
log.info("value={}", 1 / 0);
}
3.MANDATORY
当前的方法必须在事务中运行,否则的话就抛出异常。
例子:
给子方法添加MANDATORY,主方法不添加事务,此时执行testMandatory方法就会抛出异常,因为addM方法没有在事务中执行。
异常:No existing transaction found for transaction marked with propagation ‘mandatory’
@Transactional(propagation = Propagation.MANDATORY)
@Override
public void addM(UsersEntity usersEntity) {
usersMapper.insert(usersEntity);
}
@Test
public void testMandatory() {
UsersEntity usersEntity = new UsersEntity();
usersEntity.setName("小明");
usersService.addM(usersEntity);
}
4.REQUIRES_NEW
当前的方法必须在自己的事务内运行,如果有其他的事务就将它挂起。
例子:
在testNew方法中抛出异常并不会造成addNew的事务回滚,因为REQUIRES_NEW会新启一个事务,不受父级的影响。
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void addNew(UsersEntity usersEntity) {
usersMapper.insert(usersEntity);
}
@Transactional(propagation = Propagation.REQUIRED)
@Test
public void testNew() {
UsersEntity usersEntity = new UsersEntity();
usersEntity.setName("小明");
usersService.addNew(usersEntity);
log.info("value={}", 1 / 0);
}
在下面的方法中将异常放在子方法中,对于添加了REQUIRES_NEW传播事务的方法还是不受影响,还是能将数据写入数据库。
@Override
public void addNew(FoodEntity foodEntity) {
log.info("value={}", 1 / 0);
foodMapper.insert(foodEntity);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void addNew(UsersEntity usersEntity) {
usersMapper.insert(usersEntity);
}
@Transactional(propagation = Propagation.REQUIRED)
@Test
public void testNew() {
UsersEntity usersEntity = new UsersEntity();
usersEntity.setName("小明");
usersService.addNew(usersEntity);
FoodEntity foodEntity = new FoodEntity();
foodEntity.setName("apple");
foodService.addNew(foodEntity);
}
5.NOT_SUPPORTED
当前的方法不会在事务中运行,如果有事务就会将它挂起。
例子:
给addNotSupport方法添加NOT_SUPPORTED,testNotSupport添加REQUIRED运行时,addNotSupport方法还是会将数据添加到数据库中,并没有采取REQUIRED回滚。
@Transactional(propagation = Propagation.NOT_SUPPORTED)
@Override
public void addNotSupport(UsersEntity usersEntity) {
usersMapper.insert(usersEntity);
}
@Transactional(propagation = Propagation.REQUIRED)
@Test
public void testNotSupport() {
UsersEntity usersEntity = new UsersEntity();
usersEntity.setName("小明");
usersService.addNotSupport(usersEntity);
log.info("value={}", 1 / 0);
}
6.NEVER
当前的方法如果在事务中运行,则抛出异常。
例子:
addNever方法在testNever方法中运行会抛出异常,因为testNever方法添加了REQUIRED。
异常:Existing transaction found for transaction marked with propagation ‘never’
@Transactional(propagation = Propagation.NEVER)
@Override
public void addNever(UsersEntity usersEntity) {
usersMapper.insert(usersEntity);
}
@Transactional(propagation = Propagation.REQUIRED)
@Test
public void testNever() {
UsersEntity usersEntity = new UsersEntity();
usersEntity.setName("小明");
usersService.addM(usersEntity);
}
7.NESTED
如果存在事务运行,那么这个方法就是在这个事务的嵌套事务内运行,嵌套事务是独立提交或回滚;
如果不存在事务,就按照REQUIRED执行;
如果主事务回滚,子事务一定会回滚;如果子事务回滚,主事务可以回滚,也可以不回滚。
例子:
在主事务中抛出异常,子事务是会跟着一起回滚事务的,这就是NESTED的嵌套事务
@Transactional(propagation = Propagation.NESTED)
@Override
public void addNested(UsersEntity usersEntity) {
usersMapper.insert(usersEntity);
}
@Transactional(propagation = Propagation.REQUIRED)
@Test
public void testNested() {
UsersEntity usersEntity = new UsersEntity();
usersEntity.setName("小明");
usersService.addNested(usersEntity);
log.info("value={}", 1 / 0);
}
在主事务中try-catch可能出现异常的子事务,那就不会影响其他事务的正常运行。如下方法 food的保存方法就可以正常保存到数据库。
@Transactional(propagation = Propagation.NESTED)
@Override
public void addNested(UsersEntity usersEntity) {
usersMapper.insert(usersEntity);
log.info("value={}", 1 / 0);
}
@Override
public void addd(FoodEntity foodEntity) {
foodMapper.insert(foodEntity);
}
@Transactional(propagation = Propagation.REQUIRED)
@Test
public void testNested() {
FoodEntity foodEntity = new FoodEntity();
foodEntity.setName("apple");
foodService.addd(foodEntity);
UsersEntity usersEntity = new UsersEntity();
usersEntity.setName("小明");
try {
// save point
usersService.addNested(usersEntity);
} catch (Exception e) {
e.printStackTrace();
}
}
事务失效的情况
- 方法不是public
- 异常类型不是unchecked
- 数据库引擎要支持事务,比如mysql的innodb
- spring能否扫描到包
- 在同一个类不要使用this.XX(方法),因为这个this并不是spring用cglib增强的类,没有被代理,那就没有事务。