【问题标题】:How N+1 issue can be resolved by introducing second-level cache in Hibernate?在 Hibernate 中引入二级缓存如何解决 N+1 问题?
【发布时间】:2015-05-26 19:40:16
【问题描述】:

performance section 的 Hibernate 文档中指出:

解决 N+1 选择问题的一种完全不同的方法是使用 二级缓存。

我不明白它如何解决问题。什么可能是现实世界的例子和解释?

【问题讨论】:

    标签: java hibernate caching jpa second-level-cache


    【解决方案1】:

    这很简单。假设您有以下领域模型:

    @Entity(name = "Post")
    public class Post {
    
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long id;
    
        private String name;
    
        @OneToMany(cascade = CascadeType.ALL, mappedBy = "post")
        private List<Comment> comments = new ArrayList<>();
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public List<Comment> getComments() {
            return comments;
        }
    
        public void addComment(Comment comment) {
            comments.add(comment);
            comment.setPost(this);
        }
    }
    
    @Entity(name = "Comment")
    public class Comment {
    
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long id;
    
        @ManyToOne
        private Post post;
    
        public Comment() {
        }
    
        public Comment(String review) {
            this.review = review;
        }
    
        private String review;
    
        public Long getId() {
            return id;
        }
    
        public Post getPost() {
            return post;
        }
    
        public void setPost(Post post) {
            this.post = post;
        }
    
        public void setReview(String review) {
            this.review = review;
        }
    }
    

    如果您运行以下 HQL 查询:

    List<Comment> comments = session.createQuery(
        "select c from Comment c ").list();
    for(Comment comment : comments) {
        Post post = comment.getPost();
    }
    

    然后,对于每个评论,您必须运行一个额外的查询来获取相关的评论帖子。

    如果您启用二级缓存:

    @Entity(name = "Post")
    @Cacheable
    @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
    public class Post {
        ...
    }
    

    然后Hibernate首先进入二级缓存加载实体,只有在没有找到缓存条目的情况下才访问数据库。

    一个更简单的解决方案是简单地fetch all required data at query-time:

    List<Comment> comments = session.createQuery(
        "select c from Comment c fetch c.post ").list();
    

    这样您就不会遇到 N+1 查询问题,也不需要二级缓存。 Like any caching solution,当数据库在 Hibernate API 之外更新时,二级缓存容易出现不一致。

    【讨论】:

      猜你喜欢
      • 2011-07-22
      • 2014-10-18
      • 2014-03-15
      • 1970-01-01
      • 2019-06-11
      • 2021-08-27
      • 2010-09-25
      • 2015-05-14
      • 2011-02-05
      相关资源
      最近更新 更多