多表关联
一对一(单向)
- 通过
@OneToOne
设置。fetch
设置是否懒加载。(fetch = FetchType.LAZY
)cascade
设置关联操作。例如设置成cascade = CascadeType.PERSIST
时,关联的对象不需要自己调用持久化方法,会自动持久化。orphanRemoval
关联删除。通常在修改的时候使用。一旦把关联的数据设置成null
,或者修改为其他的数据,旧的数据会被删除。默认为false
。optional
设置关联的对象是否可以为空。默认为true
。用来限制关联的对象不能为null
。
- 外键名称通过
@JoinColumn
设置。
一对一(双向)
- 基本使用方法参照一对一单向。
- 设置双向关联不能在两个表里都设置外键(
@JoinColumn
),因为两个表互相有外建约束会造成两个表里的数据都无法删除。- 要在其中一个表里放弃外键约束,把
Id
设置成不受另一个表约束的数值,或者把外键删除。
- 要在其中一个表里放弃外键约束,把
- 放弃外键约束可以用
@OneToOne(mappedBy = "...")
,将外键约束交给另一方维护。
一对多/多对一
@OneToMany
和@ManyToOne
,注解参数参照上面的一对一。@JoinColumn
虽然应该定义在"多"的一方,但是单向的一对多也可以定义在"一"的一方。定义在"一"的时候会在"多"的表里生成外键。(https://javaee.github.io/javaee-spec/javadocs/javax/persistence/JoinColumn.html)
// 多对一的时候定义的是在本表指向另一方主键的外键名。
@ManyToOne
@JoinColumn(name="ADDR_ID")
public Address getAddress() { return address; }
// 比如顾客有很多订单,要在顾客这一方维护单向一对多,定义的是在订单表的外键。
@OneToMany
@JoinColumn(name="CUST_ID") // join column is in table for Order
public Set<Order> getOrders() {return orders;}
- 一对多默认是懒加载。
单向和双向有什么区别?
这篇文章有详细的解释。 https://www.baeldung.com/jpa-joincolumn-vs-mappedby
- 无论单向还是多向,它对数据库的映射是没有影响的。它仅仅是定义了领域模型(domain model)里的关系。
- 对于双向关系,我们一般定义所有方(owning side)与参照方(inverse or referencing side)。
@JoinColumn
定义的是所有方,而mappedBy
属性定义了参照方。- 在一对多或者多对一的关系中,所有方一般定义在多的一方,就是说
many
的那一方一般拥有外键的定义。比如说一个员工可以有很多个电子邮件,@JoinColumn
就定义在电子邮件这一方,它有一个叫做employee_id
的外键指向Employee
的主键。需要注意mappedBy
的值应为所有方里定义的属性名。
@Entity
public class Email {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "employee_id")
private Employee employee;
// ...
}
@Entity
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "employee")
private List<Email> emails;
// ...
}
- 另外还有一些补充,双向绑定并不是最好的,比如数据很多的时候,应该需要做一些分页或者筛选。 https://stackoverflow.com/questions/5360795/what-is-the-difference-between-unidirectional-and-bidirectional-jpa-and-hibernat