一文搞定,详细说明JPA实体关系映射

系列文章目录

  1. JPA常用基础注解说明
  2. 一文搞定,详细说明JPA实体关系映射


前言

正常开发中,经常会遇到多表关联操作,一下将对各个关系进行解释说:

实体关系注解
一对一@OneToOne
一对多,多对一@OneToMany,@ManyToOne
多对多@ManyToMany

1. @OneToOne

1.1属性说明:

  • targetEntityClass:表示默认关联的实体类型,默认为当前标注的实体类
  • cascade:关联属性,这个属性定义了当前类对象操作了之后,级联对象的操作。级联可取值如下:
    • 不定义:对关系表不会产生任何影响
    • CascadeType.PERSIST:级联新建
    • CascadeType.REMOVE:级联删除
    • CascadeType.REFRESH:级联刷新
    • CascadeType.MERGE:级联更新
    • CascadeType.ALL:表示同事选择了上述的所有级联操作
  • fetch:FetchType 类型的属性
    • FetchType.EAGER:表示关系类在主类加载的时候同时加载
    • FetchType.LAZY:表示关系类在被访问时才加载,默认值是 FetchType.LAZY
  • mappedBy:定义在双向 @OneToOne,双向 @OneToMany,双向 @ManyToMany,值为子表的属性
  • orphanRemoval:指定在删除一方(One)数据的同时是否删除掉多方(Many)的数据。默认为 false,不删除多方(Many)数据;仅仅将一方(One)和连接表的数据进行删除

1.2 实体说明

实体 People :用户。
实体 Address:家庭住址。
People 和 Address 是一对一的关系。

@OneToOne 作用:用于映射一对一关系
   属性:
     cascade:配置级联操作。
@JoinColumn 作用:声明关联关系
   属性:
     name:当前表的字段(用于存储外键的信息)
     referencedColumnName:引用表对应的字段,如果不注明,默认就是引用表的主键

用户实体 People

@Entity
@Table(name = "people")
public class People {
    @Id
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid", strategy = "org.hibernate.id.UUIDGenerator")
    private String uuid;
    
    private String name;//姓名
    
    private String sex;//性别
    
    private Timestamp birthday;//出生日期
    
    //People是关系的维护端,当删除 people,会级联删除 address
    @OneToOne(cascade=CascadeType.ALL)
    //people中的address_id字段参考address表中的id字段
    @JoinColumn(name = "address_id", referencedColumnName = "id")
    private Address address;//地址
}

地址实体 Address

mappedBy:
   只有OneToOne,OneToMany,ManyToMany上才有mappedBy属性,ManyToOne不存在该属性;
   mappedBy标签一定是定义在被拥有方的,他指向拥有方;
   mappedBy的含义,应该理解为,拥有方能够自动维护跟被拥有方的关系,当然,如果从被拥有方,通过手工强行来维护拥有方的关系也是可以做到的;
   mappedBy跟joinColumn/JoinTable总是处于互斥的一方,可以理解为正是由于拥有方的关联被拥有方的字段存在,拥有方才拥有了被拥有方。mappedBy这方定义JoinColumn/JoinTable总是失效的,不会建立对应的字段或者表。

@Entity
@Table(name = "address")
public class Address {
    @Id
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid", strategy = "org.hibernate.id.UUIDGenerator")
    private String uuid;
    
    private String zipcode;//邮政编码
    
    private String address;//地址
    
    //如果不需要根据Address级联查询People,可以注释掉
//    @OneToOne(mappedBy = "address", cascade = {CascadeType.MERGE, CascadeType.REFRESH}, optional = false)
//    private People people;
}

2. @OneToMany,@ManyToOne

2.1 实体说明

实体 Author:作者。
实体 Article:文章。
Author 和 Article 是一对多关系(双向)。

JPA使用@OneToMany和@ManyToOne来标识一对多的双向关联。一端(Author)使用@OneToMany,多端(Article)使用@ManyToOne。
在JPA规范中,一对多的双向关系由多端(Article)来维护。就是说多端(Article)为关系维护端,负责关系的增删改查。一端(Author)则为关系被维护端,不能维护关系。
一端(Author)使用@OneToMany注释的mappedBy="author"属性表明Author是关系被维护端。

作者实体:Author

@Entity
public class Author {
    @Id
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid", strategy = "org.hibernate.id.UUIDGenerator")
    private String uuid;
    
    private String name;//姓名
    
    @OneToMany(mappedBy = "author",cascade=CascadeType.ALL,fetch=FetchType.LAZY)
    //级联保存、更新、删除、刷新;延迟加载。当删除用户,会级联删除该用户的所有文章
    //拥有mappedBy注解的实体类为关系被维护端
     //mappedBy="author"中的author是Article中的author属性
    private List<Article> articleList;//文章列表
}

文章实体:Article

@Entity
public class Article {
    @Id
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid", strategy = "org.hibernate.id.UUIDGenerator")
    private String uuid;
    
    private String title;

    private String content;//文章全文内容
    
    @ManyToOne(cascade={CascadeType.MERGE,CascadeType.REFRESH},optional=false)//可选属性optional=false,表示author不能为空。删除文章,不影响用户
    @JoinColumn(name="author_id")//设置在article表中的关联字段(外键)
    private Author author;//所属作者
}

3. @ManyToMany

实体 Student:学生。
实体 Student:课程。
Student和 Student是多对多关系(双向)。

3.1 实体说明

@ManyToMany 作用:用于映射多对多关系
  属性:
    cascade:配置级联操作。
    fetch:配置是否采用延迟加载。
    targetEntity:配置目标的实体类。映射多对多的时候不用写。
@JoinTable 作用:针对中间表的配置
  属性:
    name:配置中间表的名称
    joinColumns:中间表的外键字段关联当前实体类所对应表的主键字段
    inverseJoinColumns:中间表的外键字段关联对方表的主键字段
@JsonIgnoreProperties(“studentList”):类级别的注解。
  指定的字段不会被序列化和反序列化。在多对多中主要为避免进入死循环

学生实体 Student

@Data
@Table
@Entity
public class Student {

    @Id
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid", strategy = "org.hibernate.id.UUIDGenerator")
    private String id;
    private String name;
    private Sex sex;
    private int age;

    @ManyToMany
    @JsonIgnoreProperties("studentList")
    @JoinTable(name = "STUDENT_COURSE", joinColumns = @JoinColumn(name = "STUDENT_ID"),inverseJoinColumns = @JoinColumn(name = "COURSE_ID"))
    private List<Course> courseList;
}

课程实体 Course

@ManyToMany属性:mappedBy
  1.只有OneToOne,OneToMany,ManyToMany上才有mappedBy属性,ManyToOne不存在该属性;
  2.mappedBy标签一定是定义在the owned side(被拥有方的),他指向theowning side(拥有方);
  3.关系的拥有方负责关系的维护,在拥有方建立外键。所以用到@JoinColumn
  4.mappedBy跟JoinColumn/JoinTable总是处于互斥的一方

@Data
@EqualsAndHashCode(callSuper = false)
@Entity
public class Course{
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid",strategy = "org.hibernate.id.UUIDGenerator")
    private String id;

    private String name; // 课程名称

    @JsonIgnoreProperties("courseList")
    @ManyToMany(mappedBy = "courseList")
    private List<Student> studentList;
}

4. CascadeType(各种级联操作)详解。

关于级联操作的说明,下文是我找到一篇比较好的说明

作者:三汪
链接:https://www.jianshu.com/p/e8caafce5445

5. 解决无限递归,进入死循环问题。

当一对多,多对一,多对多情况时,为了避免进入死循环,有两个解决方案:

  1. 破坏某一方的 toString() 方法即可,最好是破坏多的一方的 toString() 方法,建议使用 @ToString(exclude = "属性名")
  2. 使用注解解决。以下对多个注解进行使用说明:
    @JsonBackReference
    @JsonManagedReference
    @JsonIgnore
    @JsonIgnoreProperties
  • @JsonBackReference标注的属性在序列化(serialization,即将对象转换为json数据)时,会被忽略(即结果中的json数据不包含该属性的内容)。
  • @JsonManagedReference标注的属性则会被序列化。
    @JsonBackReference和@JsonManagedReference:这两个标注通常配对使用,通常用在父子关系中
  • @JsonIgnore 直接忽略某个属性,以断开无限递归,序列化或反序列化均忽略。
  • @JsonIgnoreProperties 忽略某个对象中的属性
    allowSetters = true 指定的逻辑属性@JsonIgnoreProperties将参与 JSON 反序列化,但不参与序列化。
    allowGetters = true 指定的逻辑属性@JsonIgnoreProperties将参与 JSON 序列化但不参与反序列化。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值