JPA 关系映射: one-two-many 双向关系的基本配置

本文基于 SpringBoot + Hibernate 下的 JPA

总的来说,就是在 @OneToMany@ManyToOne 注解的基础上结合使用两者。下面以 LeadAttachment 两个实体为例进行说明,即一个 Lead 和多个 Attachment 双向关联。

@Entity
@Table(name = "lead")
public class Lead {
  @OneToMany
  private List attachmentList = new ArrayList<>();
}

@Entity
@Table(name = "attachment")
public class Attachment {
  @ManyToOne
  private Lead lead;
}

One 端,即 Lead 中使用 @OneToMany 注解,而在 Many 端,即 Attachment 中使用 @ManyToOne 注解。

关联媒介

我们知道关系的关联媒介有两种

  • 通过中间表关联,由 @JoinColumn 配置
  • 通过外键关联,由 @JoinTable 配置

而在双向关系中,这两个注解加在 @OneToMany 端才有效,即此时关联媒介由 One 端决定。下面以 @JoinColumn 为例,其 name 属性指定了 Many 端表中生成的外键的字段名。

@OneToMany
@JoinColumn(name="lead_id")
private List attachmentList = new ArrayList<>();

@ManyToOne
private Lead lead;

如果 @OneToMany 没有这两个注解,则按照 @OneToMany 单向时的默认情况, Hibernate 会自动生成中间表。

关系维护

在上述的配置下,关联关系由两端同时进行维护,这样会产生额外的 update 语句。解决办法就是 One 端将维护权交由 Many 端,通过 @OneToManymappedBy 属性实现, 其值为 Many 端实体中关系对应的字段名,这里为 lead

@OneToMany(mappedBy = "lead"))
private List attachmentList = new ArrayList<>();

@ManyToOne
private Lead lead;

由于 mappedBy 属性和 @JoinColumn 互斥,所以 @OneToMany 不能再加 @JoinColumn, 何况此时的关联方式转由 @ManyToOne 决定,所以要实现指定外键关联,则给 @ManyToOne 添加 @JoinColumn

@OneToMany(mappedBy = "lead"))
private List attachmentList = new ArrayList<>();

@ManyToOne
@JoinColumn(name="lead_id")
private Lead lead;

Many 端的懒加载

上述配置下,还会产生另外一个问题。假设有一个孤立 Attachment 存在数据库中,即没有关联任何 Lead。此时通过 JPA 接口的 findById 方法是找不到这个 Attachment 的。因为 @ManyToOne 的级联查询默认是饥饿获取,查找的同时会与 Lead 进行 join,而由于关联关系还不存在,所以自然找不到。解决办法就是将 @ManyToOnefetch 属性设置为 FetchType.LAZY,即懒加载。

@OneToMany(mappedBy = "lead"))
private List attachmentList = new ArrayList<>();

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="lead_id")
private Lead lead;

你可能感兴趣的:(JPA 关系映射: one-two-many 双向关系的基本配置)