事务嵌套异常-Transaction rolled back because it has been marked as rollback-only
1.问题出现场景
新增系统角色需要审计通过之后才能执行具体逻辑,审计方法上面有事务,然后对应新增逻辑也有对应事务,因为新增失败时需要更新审计状态,以及记录审计日志,所以对新增逻辑进行了try-catch捕捉,然后新增逻辑报错导致出现这个异常。
2.代码例子
新增代码接口
@Override
@Transactional(rollbackFor = {Exception.class}, propagation = Propagation.REQUIRED)
public Role addRole(NexusRequest<AddRoleFrom> nexusRequest) {
UserDetailVO me = jwtTokenProperties.getCurrentUserDetailVO();
AddRoleFrom addRoleFrom = nexusRequest.getPayload();
long count = this.count(new LambdaQueryWrapper<Role>()
.eq(Role::getMerCode, me.getMerCode())
.eq(Role::getRoleName, addRoleFrom.getRoleName()));
if (count>0){
throw new CrmException("该角色已存在");
}
Role role = new Role();
role.setRoleName(addRoleFrom.getRoleName());
role.setMerCode(me.getMerCode());
role.setValidBeginDate(LocalDate.now());
role.setRemark(addRoleFrom.getDescription());
role.setSort(addRoleFrom.getSort());
this.save(role);
//这里新增其他角色相关表. 涉及业务删除了
return role;
}
审计代码
@SneakyThrows
@Override
@Transactional(rollbackFor = {Exception.class}, propagation = Propagation.REQUIRED)
public Boolean verify(NexusRequest<AuditVerifyForm> nexusRequest) {
try {
AddRoleFrom form = objectMapper.readValue(auditVersion.getReqData(), new TypeReference<AddRoleFrom>() {
});
NexusRequest<AddRoleFrom> request = new NexusRequest<>();
request.setTraceId(nexusRequest.getTraceId());
request.setTimestamp(nexusRequest.getTimestamp());
request.setPayload(form);
//调用新增角色接口
roleService.addRole(request);
//更新审计状态
crmAuditMapper.updateBackStatusById(crmAudit.getId(), VerifyStatusEnum.Normal.getValue());
} catch (Exception e) {
log.error("审批失败{},{}", auditType.getTypeCode(), e.getMessage());
//更新审计失败状态
crmAuditMapper.updateBackStatusById(crmAudit.getId(), VerifyStatusEnum.Fail.getValue());
//更新审计日志状态,以及失败原因
crmAuditLogService.updateAuditLogStatus(auditLog.getId(), VerifyStatusEnum.Fail.getValue(), e.getMessage());
}
}
3.解决办法
-
第一种: 删除新增角色接口里面的事务, 但是我们在新增角色表有其他的新增,要保持事务一致性, 肯定不能删除.
-
第二种: 在审计接口catch使用 throw new CrmException 把异常抛出. 但是我们审计接口最下面还有其他执行逻辑不能抛出
-
第三种: 更改新增角色接口里面的事务策略, 把propagation = Propagation.REQUIRED 改为propagation = Propagation.REQUIRED_NEW
@Override
@Transactional(rollbackFor = {Exception.class}, propagation = Propagation.REQUIRES_NEW)
public Role addRole(NexusRequest<AddRoleFrom> nexusRequest) {
UserDetailVO me = jwtTokenProperties.getCurrentUserDetailVO();
AddRoleFrom addRoleFrom = nexusRequest.getPayload();
long count = this.count(new LambdaQueryWrapper<Role>()
.eq(Role::getMerCode, me.getMerCode())
.eq(Role::getRoleName, addRoleFrom.getRoleName()));
if (count>0){
throw new CrmException("该角色已存在");
}
Role role = new Role();
role.setRoleName(addRoleFrom.getRoleName());
role.setMerCode(me.getMerCode());
role.setValidBeginDate(LocalDate.now());
role.setRemark(addRoleFrom.getDescription());
role.setSort(addRoleFrom.getSort());
this.save(role);
//这里新增其他角色相关表. 涉及业务删除了
return role;
}