在处理业务代码时,经常遇到要编辑主子表的问题。以前遇到这个问题的时候处理方式很简单,先根据主表id删除子表数据,再把前台传入的子表信息批量入库。以学生和班级为例(下同),一个班级有多个学生,即对应数据库的班级是主表,学生是子表。为了表述方便,省略了非关键判断。代码如下:
// 更新主表信息
classAndGradeMapper.update(classAndGradeMapper)
// 根据主表id删除子表信息
String classAndGradeId = classAndGrade.getId();
studentMapper.deleteByClassAndGradeId(classAndGradeId);
// 再批量新增
studentMapper.batchInsert(insertList);
似乎是解决了问题。但这种处理方式“简单粗暴”,只适用于学生的信息“永远”不会被使用,而且无关紧要。即满足了“学生表的id永远不会被使用”这一真理。
但真实的情况真的是这么简单吗?答案并非如此。学生的考试成绩,选的课程,联系信息等等,都和学生的id有着必然的联系......
那么就必须确保编辑时子表(学生表的id)不能被轻易更改,我称之为“子表id守护”。
// 更新主表信息
classAndGradeMapper.update(classAndGradeMapper);
// 主表id
String classAndGradeId = classAndGrade.getId();
// 1定义要批量删除的数据的集合
List<String> deleteList = new ArrayList<>();
// 2定义要批量新增的数据的集合
List<Student> insertList = new ArrayList<>();
// 3定义要批量更新的数据的集合
List<Student> updateList = new ArrayList<>();
// 4根据主表id,查询所有子表id
List<String> oldStudentIds = studentMapper.findIdsByClassAndGradeId(classAndGradeId);
// 5.获取前台传入的所有子表的id
List<String> newStudentIds = new ArrayList<>();
introductionStudents.forEach(e->{
newStudentIds.add(e.getId());
});
// 6比较旧id和新的id是否相等,调用已经有的方法
if (SystemUtils.listIsEquals(oldStudentIds, newStudentIds)) {
// 6.1说明集合是相等的,并且没有null存在,这个时候全部批量更新
studentMapper.batchUpdate(introductionStudents);
}else{
// 6.2
if (newStudentIds.containsAll(oldStudentIds)) {
// 要更新的集合真包含原集合,说明本次有新增。此时,需要更新原有的数据,新增新数据
doAddAndUpdateList(insertList, updateList,otherParams);
}else if(oldStudentIds.containsAll(newStudentIds)){
// 有要删除的.此时,需要删除已经删除的数据,更新未删除的数据
doDeleteAndUpdateList(deleteList, updateList,otherParams);
}else{
// 既有新增,又有删除。同时执行上述方法。
doAddAndUpdateList(insertList, updateList,otherParams);
doDeleteAndUpdateList(deleteList, updateList,otherParams);
}
}
主体方法已经完成。接下来是两个do方法,在do方法中需要分别取出哪些是新增的,哪些是编辑的,哪些是修改的。再调用数据库的批量操作。
private void doAddAndUpdateList(List<Student> introductionStudents, List<String> oldId,
List<Student> insertList, List<Student> updateList){
for (Student s : introductionStudents) {
String id = s.getId();
if(oldId.contains(id)) {
// 编辑
updateList.add(s);
}else {
// 新增
insertList.add(s);
}
}
// 分别新增和编辑
studentMapper.batchInsert(insertList);
studentMapper.batchUpdate(updateList);
}
private void doDeletAndUpdateList(List<Student> introductionStudents,
List<String> oldIds,List<String> newIds,List<String> deleteList,
List<Student> updateList) {
// 遍历旧的集合
for (String oldId : oldIds) {
// 如果新的里有这条记录,说明是要编辑
if (newIds.contains(oldId)) {
// 在新的中取出要编辑的数据
for (Student introductionStudent : introductionStudents) {
if(Objects.equals(oldId,introductionStudent.getId())){
// 编辑
updateList.add(introductionStudent);
}
}
} else {
// 删除
deleteList.add(oldId);
}
}
// 分别编辑和删除
studentMapper.deleteBatch(deleteList);
studentMapper.batchUpdate(updateList);
}
至此,核心代码已经完毕。因篇幅有限,没有详细列出代码,用到的时候还需要进行判空、合理值校验、事务处理等工作。当然,代码还可以进行优化的哦。
【以此记录,以备后用】