由于这是一个非常常见的问题,因此我写了
这篇文章,此答案基于此。
单向一对多关联
正如我在本文中所解释的,如果将@OneToMany
注释与一起使用@JoinColumn
,则您将具有单向关联,例如下图中的父Post
实体和子实体之间的关联PostComment
:
使用单向一对多关联时,只有父侧会映射该关联。
在此示例中,仅Post
实体将定义与子实体的@OneToMany
关联PostComment
:
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "post_id")
private List<PostComment> comments = new ArrayList<>();
双向一对多关联
如果@OneToMany
与mappedBy
属性集一起使用,则将具有双向关联。在我们的示例中,两个Post
实体都有一个PostComment
子实体集合,并且该PostComment
子实体具有对父Post
实体的引用,如下图所示:
在PostComment
实体中,post
实体属性映射如下:
@ManyToOne(fetch = FetchType.LAZY)
private Post post;
我们将fetch
属性显式设置为的原因FetchType.LAZY
是,由于默认情况下,所有@ManyToOne
和@OneToOne
关联都被急切获取,这可能会导致N + 1查询问题。有关此主题的更多详细信息,请参阅本文。
在Post
实体中,comments
关联映射如下:
@OneToMany(
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();
在mappedBy
该属性@OneToMany
注释引用post
属性在儿童PostComment
实体,而且这样一来,Hibernate知道了双向关联是由控制@ManyToOne
一面,这是负责管理这个表的关系是基于外键列值。
对于双向关联,您还需要具有两个实用程序方法,例如addChild
和removeChild
:
public void addComment(PostComment comment) {
comments.add(comment);
comment.setPost(this);
}
public void removeComment(PostComment comment) {
comments.remove(comment);
comment.setPost(null);
}
这两种方法可确保双向关联的两端不同步。如果不同步两端,则Hibernate无法保证关联状态更改将传播到数据库。
有关使双向关联与JPA和Hibernate同步的最佳方法的更多详细信息,请参阅本文。
选择哪一个?
该单向@OneToMany
协会不执行得很好,所以你应该避免。
您最好使用更高效的双向@OneToMany
。