@OneToOne (bidirectional)

假设有学生学费两张表:

一个学生只能有一个学费要缴纳,一个学费也只要求特定的一名学生缴纳。所以这是一个一对一关系

概念:

  • 关系的拥有者/关系的维护者/owning side

    拥有外键的表即是关系的拥有者,并且还是关系的维护者。

  • Parent Table/non-owning side

    有孩子,没爸妈,那当然是不可能的。

    对于 student 和 tuition 也是这样。如果有一个 tuition 没有 student,那是不可能的,都没有学生哪来的收学费这一说呢。

    在这种情形下 student 表是 Parent Table

  • 关系的拥有者一般都是 Child Table,而不是 Parent Table。

来看代码:

@Entity
@Table(name = "student")
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String name;

    @OneToOne(mappedBy = "student", cascade = CascadeType.ALL, orphanRemoval = true, fetch=FetchType.LAZY)
    private Tuition tuition;

    /* Getters and setters */   
}
@Entity
@Table(name = "tuition")
public class Tuition {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private Double fee;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "student_id")
    private Student student;

    /* Getters and setters */    
}
  • @OneToOne

    • mappedBy = "student"

      如果不在 Parent Table 或者说 non-owning side 使用 mappedBy 的话,这就是一个单项关系(虽然 @OneToOne 不存在单项关系)。mappedBy 的值应该是 owning side 外键的实例域名(实际来自 getters 或 setters)。

    • cascade = CascadeType.ALL

      cascade 会赋予当前实体操作另一个实体内容的权限。

      JPA Cascade Types:

      • CascadeType.ALL 所有级联操作

        拥有全部权限。

      • CascadeType.REMOVE 级联删除操作

        删除当前实体时,与它有映射关系的实体也会被跟着删除。

        在这里表示,如果当前 student 被删除,其 tuition 实体也会被删除,很合理。

      • CascadeType.MERGE 级联更新(合并)操作

        当前实体中的数据改变时,会相应的更新与它有映射关系的实体的数据。

      • CascadeType.DETACH 级联脱管/游离操作

        意思是,分离所有相关联的实体,该实体已在数据库中,对象将处于分离状态,对该对象的操作不会同步到数据库。

      • CascadeType.REFRESH 级联刷新操作

        假设场景:有一个订单,订单里面关联了许多商品,这个订单可以被很多人操作,那么这个时候 A 对此订单和关联的商品进行了修改,与此同时,B 也进行了相同的操作,但是 B 先一步比 A 保存了数据,那么当 A 保存数据的时候,就需要先刷新订单信息及关联的商品信息后,再将订单及商品保存。

    • orphanRemoval = true

      刚刚说到,student 表是 Parent Table,如果某个 student 没了,也就是没了爹妈,其关联的 tuition 实体就成了孤儿,变孤儿了就要被删除了。

    • fetch=FetchType.LAZY

      懒加载,只有真正需要调用的时候才会真正从数据库里拉取数据。

      JPA Fetch Types:

      • FetchType.LAZY 懒加载

        懒加载,加载一个实体时,定义懒加载的属性不会马上从数据库中加载。

      • FetchType.EAGER 急加载

        急加载,加载一个实体时,定义急加载的属性会立即从数据库中加载。

      • 使用场景

        比方 User 类有两个属性,name 跟 address。比如百度知道,登录后用户名是需要显示出来的,此属性用到的几率极大,要马上到数据库查,用急加载

        用户地址大多数情况下不需要显示出来,只有在查看用户资料是才需要显示,需要用了才查数据库,用懒加载就好了。

        所以,并不是一登录就把用户的所有资料都加载到对象中,于是有了这两种加载模式。

  • @JoinColumn(name = "student_id")

    @JoinColumn 表示 tuition 这边要为这个外键关系单独加一列,名字叫 student_id

    对比 mappedBy 来说,@JoinColumn 定义的是 owning side 实际的物理映射。而 mappedBy 定义的是 non-owning side 的引用。

    经过实际测试,@JoinColumn 其实没有也行,JPA 也会为我们自动生成一列 student_id

最后更新于