源码注释
源码说,创建一个新事务,如果已存在一个事务,会将上层的事务挂起(暂停),意思就是你玩你的,我玩我的。
/**
* Create a new transaction, suspending the current transaction if one exists.
* Analogous to the EJB transaction attribute of the same name.
* <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
* on all transaction managers. This in particular applies to
* {@link org.springframework.transaction.jta.JtaTransactionManager},
* which requires the {@code jakarta.transaction.TransactionManager} to be
* made available it to it (which is server-specific in standard Jakarta EE).
* <p>A {@code PROPAGATION_REQUIRES_NEW} scope always defines its own
* transaction synchronizations. Existing synchronizations will be suspended
* and resumed appropriately.
* @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
*/
int PROPAGATION_REQUIRES_NEW = 3;
测试环境
jdk17+mysql8+spring5.2
controller
定义一个controller,就为了方便调用service
@RestController
@RequestMapping("/api/test")
@Api(value = "测试", tags = "测试")
class StudentController extends ZubusBaseApi {
@Autowired
MutService mutService;
@RequestMapping(value = "/add", method = RequestMethod.PUT)
public ApiResult testUpdateUser(@RequestBody SysUser user) {
user = new SysUser();
user.setUserID(1L);
user.setUserName("懒羊羊");
Integer updateUserName = mutService.testUpdateUser(user);
return new ApiResult().success(updateUserName);
}
}
定义一个mutService
为了聚合两个不同service,很多人为了省事,在同一个service里面测试,很容易因为自调用导致事务失效而影响测试结果,详情请参考@Transactional 事务失效场景分析
@Service
public class MutService {
@Autowired
SysUserService sysUserService;
@Autowired
SysUserService2 sysUserService2;
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public Integer testUpdateUser(SysUser user) {
Integer res = sysUserService.updateUser(user);// 熊大 改为懒羊羊
Integer delUserById = sysUserService2.delUserById(97L);// 熊二 改为喜羊羊 抛异常
// 模拟异常
//int a = 1/0;
return res + delUserById;
}
}
SysUserService
@Service
public class SysUserService {
@Autowired
private SysUserMapper mapper;
@Transactional(propagation = Propagation.REQUIRES_NEW)
public Integer updateUser(SysUser user) {
return mapper.updateUser(user);
}
}
SysUserService2
@Service
public class SysUserService2 {
@Autowired
private SysUserMapper mapper;
/**
* 内层方法
* @param userID
* @return
*/
@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
public Integer delUserById(Long userID) {
SysUser user = new SysUser();
user.setUserID(userID);
user.setUserName("喜羊羊");
Integer deleteById = mapper.updateById(user);
// 模拟异常
//int a = 1/0;
return deleteById;
}
}
数据准备
在数据库准备两天数据,一条名字叫熊大,一条名字叫熊二
测试
外无内有,内异常
即mutService不加 Transactional 注解,而 sysUserService和sysUserService2均有注解,传播特性均为 REQUIRES_NEW,且在sysUserService2里面模拟一个异常
测试结果报错,/ by zero
查看数据库数据
熊大被改成了懒羊羊,而熊二没有,说明在外部没有事务的情况下,内部事务的异常不会影响外部。
内外皆有,内异常
将数据恢复原样,把mutService的事务注解开启,其余和上面一样
测试结果,依旧报异常
查看数据库数据
依旧是熊大被改成了懒羊羊,而熊二没有,说明在外部有事务的情况下,内部事务的异常也不会影响外部。
内外皆有,外异常
内外均开启 Transactional 注解 ,把内部异常注释,在外部模拟一个异常
与预期一致,报了异常
查看数据库数据
两个数据都正常提交了,说明在 REQUIRES_NEW 传播行为下,内外事务是独立的,互不干扰。