引入二级缓存如何解决Hibernate中的N+1问题?

6
在Hibernate文档的性能部分中提到:

解决N+1查询问题的完全不同的方法是使用二级缓存。

我不明白它如何解决问题。可以给出一个现实世界的例子和解释吗?
1个回答

3
很简单。假设您拥有以下领域模型:
@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首先访问第二级缓存以加载实体,只有在没有缓存条目时才会访问数据库。
一个更简单的解决方案是在查询时直接获取所有所需数据
List<Comment> comments = session.createQuery(
    "select c from Comment c fetch c.post ").list();

这样就不会遇到N+1查询问题,也不需要第二级缓存。像任何缓存解决方案一样,当数据库在Hibernate API之外更新时,第二级缓存容易出现不一致的情况。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接