前言:
在网上跟着一个up主用SpringBoot+JPA Repository写了小而美个人博客系统,后面在测试时发现,删除某些博客时会报错1451 - Cannot delete or update a parent row: a foreign key constraint fails ("blog .t blog. tag~, CONSTRAINT
^FKcbuwvhv 1i26t8olpvqwwarv7p^ FOREIGN KEY (blogs_ id) REFERENCES 't blog^ (id))
花了一两天的时间才把这个问题解决....个人比较笨qnq
原因分析:
从报错的字面意思来理解就是因为该博客和其他表存在依赖关系,分析自己的数据库,t_comment表依赖于t_blog表的id,所以在删除博客之前应该先把该博客对应的评论删掉。
但事情没这么简单,因为各评论之间有“回复”和”被回复“的依赖关系,由父评论和子评论构成,在删除父评论之前,应该先把子评论删除。
如下图,44的parent_comment_id=43,说明43(父评论)被44(子评论)回复过,所以他们之间存在依赖关系,应先删除44,在删除43;
但事情还要更复杂一些,当我删除44时,发现它还同时被45,46,47依赖,所以...需要使用到递归来查找子评论并删除。
代码实现:
BlogServiceImpl.java
@Transactional
@Modifying
@Override
public void deleteBlog(Long id) {
// Sort sort = Sort.by(Sort.Direction.DESC, "createTime");
//通过blog的id中找出博客下面的评论
List<Comment> byBlogId = commentRepositoryl.findByBlogId(id);
//递归查找并删除该评论的子评论,即如果该评论有子节点,就说明这条评论和其他评论还有依赖关系,必须先删除对应的子评论
findParentsAndDelete(byBlogId);
//批量删除漏网之鱼
commentRepositoryl.deleteInBatch(byBlogId);
//最后删除blog
blogRepository.deleteById(id);
}
@Transactional
@Modifying
public void findParentsAndDelete(List<Comment> comments) {
// List<Comment> parentComment;
//遍历parentComment_id=null的评论集合,并删除所有和他们有依赖关系的评论
for (Comment com:comments) {
//select * from t_comment c where com.gteId=c.parentComment_id
Optional<Comment> curCom = commentRepositoryl.findById(com.getId());
//判断是否为空
if(curCom.isPresent()){
List<Comment> parentComment = commentRepositoryl.findCommentByIdAndParentId(com.getId());
if(parentComment.isEmpty()){
//如果parentComment为空,则说明该评论和其他评论没有依赖关系,直接删除
commentRepositoryl.deleteById(com.getId());
}else{
//否则递归查询并删除和该评论有依赖的评论
findParentsAndDelete(parentComment);
}
}
}
}
CommentRepository.java
public interface CommentRepository extends JpaRepository<Comment,Long> {
List<Comment> findByBlogIdAndParentCommentNull(Long blogId, Sort sort);
@Query("select c from Comment c where c.blog.id=?1")
List<Comment> findByBlogId(Long id);
@Query("select c from Comment c where c.nickname=?1 and c.email=?2")
List<Comment> findByNicknameAndEmail(String nickname,String email);
//找出parent_id=id的评论
@Query("select c from Comment c where c.parentComment.id=?1")
List<Comment> findCommentByIdAndParentId(Long id);
}
BlogController.java
@GetMapping("/blogs/{id}/delete")
public String delete(@PathVariable Long id,RedirectAttributes attributes){
blogService.deleteBlog(id);
attributes.addFlashAttribute("message","删除成功");
return "redirect:/admin/blogs";
}