前言
`需求如下:
有一张依赖表,记录了数据之间的依赖关系。
但是数据在insert这张表之前,需要检查,将要插入表中的依赖数据,是否会引起循环依赖。
一、什么是循环依赖
如图所示:
1 指向 2
2 指向 3
3 指向 1
形成了有向闭环,此时就循环了
如果这个数据保存在数据库中,需要根据1找到所有依赖的数据(会造成死循环)。
二、循环检查
1:先造数据
数据库中的数据
对应生成的图
2:循环检查实现
@PostMapping(value = "check/cyclic")
public BaseResponse checkDependenceCyclic(@RequestBody DependenceSaveRequest request) throws CheckException {
checkCyclic(request.getSourceId(), Collections.singletonList(request.getDependenceId()));
return new BaseResponse(Msg.SUCCESS);
}
/**
* 递归检查,是否存在循环依赖
*/
private void checkCyclic(Long sourceId, List<Long> dependenceIds) throws CheckException {
List<Long> dependenceIdsBySourceIds = getDependenceIdsBySourceIds(dependenceIds);
if (CollectionUtils.isEmpty(dependenceIdsBySourceIds)) {
return;
}
if (dependenceIdsBySourceIds.contains(sourceId)) {
throw new CheckException(Msg.ERROR, "数据循环依赖");
}
checkCyclic(sourceId, dependenceIdsBySourceIds);
}
private List<Long> getDependenceIdsBySourceIds(List<Long> sourceIds) {
if (CollectionUtils.isEmpty(sourceIds)) {
return Collections.emptyList();
}
return dependenceService.list(new LambdaQueryWrapper<Dependence>()
.eq(Dependence::getDelFlag, 0)
.in(Dependence::getSourceId, sourceIds))
.stream()
.map(Dependence::getDependenceId)
.distinct()
.collect(Collectors.toList());
}
//单条新增数据 请求对象
@Data
public class DependenceSaveRequest extends BaseQuery {
/**
* 原数据id
**/
private Long sourceId;
/**
* 依赖id
**/
private Long dependenceId;
}
//数据库对象
@Data
public class Dependence {
/**
* 主键id
**/
private Long id;
/**
* 原数据id
**/
private Long sourceId;
/**
* 依赖id
**/
private Long dependenceId;
/**
* 是否删除:0-否,1-是
**/
@TableLogic
@TableField(fill = FieldFill.INSERT)
private Integer delFlag;
}
3:验证结果
插入: 9 指向 8
插入: 6 指向 3
插入: 2 指向 6
插入: 9 指向 10
总结:
这里只实现了:单条数据 插入前的检查。
还有批量数据 插入前的检查(需要返回出哪条数据导致的循环依赖)。
检查依赖表中是否已存在循环依赖的数据(需要指出造成循环依赖的数据有哪些)。