Spring Boot 服务未从存储库执行 deleteBy

Posted

技术标签:

【中文标题】Spring Boot 服务未从存储库执行 deleteBy【英文标题】:Spring boot service not executing deleteBy from repository 【发布时间】:2021-11-22 13:24:26 【问题描述】:

我正在做一个包含帖子和 cmets 的提要 帖子实体

public class Post extends AuditEntity 
    @Lob
    private String text;

    @Column
    private int totalCmnts = 0;

    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "post_id")
    private Set<Comment> comments;

    @ManyToOne
    @JoinColumn(name = "user_id", referencedColumnName = "id")
    private MEUser MEUser;


评论实体

public class Comment extends AuditEntity 
        @Lob
        private String text;
    
        @ManyToOne
        @JoinColumn(name = "user_id", referencedColumnName = "id")
        private MEUser MEUser;
    

并且我有一个服务来删除我获取帖子和评论的评论,我检查当前用户是否可以执行操作然后我删除评论并减少帖子实体中 cmets 的总数。

日志中的问题我可以看到选择操作和更新操作,但删除根本没有执行,仍然在服务类中获得带有@transactional 注释的 HTTP 200

我尝试了一个 SQL 查询,它运行良好

DELETE FROM `db-engine`.comment WHERE comment.id = 2

服务

@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()))) 

        commentsRepository.deleteById(comment.getId());
        post.setTotalCmnts(post.getTotalCmnts() - 1);
        System.out.println(comment.getId());
        System.out.println("hello");

    

【问题讨论】:

不是通过 CommentsRepository 显式删除评论,而是从 Post 实体的 comments 集合中删除评论。当 JPA 在事务结束时刷新时,它将从 comment 表中删除该行。 【参考方案1】:

问题是您将post 实体更改为post.setTotalCmnts(post.getTotalCmnts() - 1);。这意味着 Hibernate 会注意到您的实体和数据库中的数据之间的差异并刷新它(从而更新数据库中的post)。 由于您在comments 上有@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true),这意味着Hibernate 会将持久操作级联到comments 实体。在此列表中,您仍然有要删除的 Comment,因此它会被再次创建(这里可能有一些 Hibernate 优化可以理解这一点,实际上并不会从数据库中删除它)。

您还需要从post comments 列表中删除要删除的Comment,如下所示:

commentsRepository.deleteById(comment.getId());
post.setTotalCmnts(post.getTotalCmnts() - 1);
post.setComments(post.getComments().remove(comment));
System.out.println(comment.getId());
System.out.println("hello");

另外,我会添加一个自定义的setComments() 方法,它会根据给定的参数实际更新totalCmnts,否则,您可能会得到不一致的数据。此外,getter 应该返回列表的副本而不是列表本身,否则,您可能会遇到一些非常讨厌的错误,因为您在其他地方更改了列表,并且此更改会在您不注意的情况下持续存在。

【讨论】:

以上是关于Spring Boot 服务未从存储库执行 deleteBy的主要内容,如果未能解决你的问题,请参考以下文章

未从 application.properties 中提取 Spring Boot JOOQ sql 方言

Spring Boot 库项目未从 /conf 文件夹中选择外部文件配置

Spring Boot 未从 application.properties 加载用户名

即使 @Transactional 放置在服务层中,Spring boot JPA 存储库也会提交代码

Spring Boot、Spring Cloud AWS 和 AWS SQS 未从队列中读取

如何在 Spring Boot 中实现通用 JPA 存储库 - 它可以自动装配到任何实体/类类型的 Spring 服务中