【发布时间】:2015-05-26 19:40:16
【问题描述】:
在 performance section 的 Hibernate 文档中指出:
解决 N+1 选择问题的一种完全不同的方法是使用 二级缓存。
我不明白它如何解决问题。什么可能是现实世界的例子和解释?
【问题讨论】:
标签: java hibernate caching jpa second-level-cache
在 performance section 的 Hibernate 文档中指出:
解决 N+1 选择问题的一种完全不同的方法是使用 二级缓存。
我不明白它如何解决问题。什么可能是现实世界的例子和解释?
【问题讨论】:
标签: java hibernate caching jpa second-level-cache
这很简单。假设您有以下领域模型:
@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 之外更新时,二级缓存容易出现不一致。
【讨论】: