Spring Boot Service调用Repository的delete方法未执行问题咨询
问题根因
该问题是JPA关联配置和持久化上下文缓存共同导致的:
- 你的
Post实体对comments集合配置了cascade = CascadeType.ALL+orphanRemoval = true,同时关联的抓取策略是FetchType.EAGER - 业务代码中先查询了
Post对象,此时JPA会把该帖子关联的所有Comment都加载到持久化上下文的缓存中 - 你直接调用
commentsRepository.deleteById()删除评论时,JPA发现当前持久化上下文中的Post的comments集合还持有该评论的引用,会判定该评论仍然是父实体的关联对象,所以直接忽略你的独立删除操作,只会执行Post的totalCmnts字段更新。
解决方案
方案1(推荐,符合JPA关联操作规范)
删除评论前先将该评论从Post的comments集合中移除,事务提交时JPA会自动根据孤儿删除配置删除对应的评论数据,不需要单独调用deleteById:
@Override public void deleteComment(Long commentID, Long postID, UserPrincipal currentUser) { Comment comment = commentsRepository.findById(commentID) .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); Post post = postsRepository.findById(postID) .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); if (comment.getMEUser().getId().equals(currentUser.getId()) || currentUser.getAuthorities().contains(new SimpleGrantedAuthority(RoleName.ROLE_ADMIN.toString())) || currentUser.getAuthorities().contains(new SimpleGrantedAuthority(RoleName.ROLE_SUPER_ADMIN.toString()))) { // 先从父实体的关联集合中移除评论 post.getComments().remove(comment); post.setTotalCmnts(post.getTotalCmnts() - 1); // 不需要单独调用deleteById,事务提交后会自动删除数据库中的评论记录 } }
方案2(调整关联配置)
如果你的业务场景不需要从Post侧级联操作评论,可修改Post实体的关联注解,关闭孤儿删除和级联删除配置,之后直接调用deleteById即可生效:
// 修改前 @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true) // 修改后 移除CascadeType.REMOVE 关闭孤儿删除 @OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH}, orphanRemoval = false)
方案3(自定义删除语句绕开持久化上下文检查)
在CommentRepository中自定义删除方法,添加@Modifying和@Query注解直接执行删除语句,绕开持久化上下文的关联校验:
@Modifying @Query(value = "delete from Comment c where c.id = :commentId") void deleteCommentById(Long commentId);
业务代码中调用自定义的删除方法即可。
内容的提问来源于stack exchange,提问作者Kousayla
相关产品推荐
相关产品推荐

