3. JPA对象关系映射 -- 级联操做

对象映射关系分为单向关系和双向关系,单向关系只在一方对象上存在对方对象,双向关系是在双方对象上存在彼此对象。java

1、单向关系

public class Department implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer departmentId;

    private String departmentCode;
    
    @OneToMany(cascade = {CascadeType.ALL})
    @JoinColumn
    private List<Employee> employeeList;
}

在没有@JoinColumn时,将多增长一个中间关系表,由此表来维护两个对象关系,增长以后只有两个表,由Employee表维护关系。默认状况下jpa会使用主键来作关联,并在子表中增长外键约束。git

2、单向关系使用code关联

在设计表结构时,主键通常会使用自增ID,但在作子表关联时因为分布式结构缘由不想使用自增ID来作关系维护,则可自定义字段code来维护关系,以下:sql

public class Department implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer departmentId;

    private String departmentCode;

    @OneToMany(cascade = {CascadeType.ALL})
    @JoinColumn(name = "departmentCode", referencedColumnName = "departmentCode")
    private List<Employee> employeeList;
}

在employee表中会增长一个department_code字段来维护关联关系。
注意:从add操做中的SQL能够看出,employee是先insert以后,再去update关系字段的,多一步update。数据库

Hibernate: insert into department (department_code, department_name) values (?, ?)
Hibernate: insert into employee (employee_code, employee_name) values (?, ?)
Hibernate: insert into employee (employee_code, employee_name) values (?, ?)
Hibernate: update employee set department_code=? where employee_id=?
Hibernate: update employee set department_code=? where employee_id=?

3、双向关系

public class Department implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer departmentId;

    private String departmentCode;

    @OneToMany(cascade = {CascadeType.ALL}, mappedBy = "department")
    private List<Employee> employeeList;
}

public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer employeeId;

    private String employeeCode;

    @ManyToOne
    private Department department;
}

使用mappedBy将去掉中间关系表,由employee维护department的关系。并发

注意事项
1.在add操做中子对象employee必须设置主对象,不然数据库层面是没有维护外键关系的,如:app

@Test
public void add(){
    Department department = Department.builder()
            .departmentCode("D001")
            .departmentName("部门1")
            .build();

    Employee employee = Employee.builder()
            .employeeCode("E001")
            .employeeName("员工1")
            .build();
    // 如无此操做,将无关联关系        
    employee.setDepartment(department);
    
    List<Employee> employeeList = new ArrayList<>();
    employeeList.add(employee);

    department.setEmployeeList(employeeList);
    departmentRepository.save(department);
}

2.此种设置是不须要额外update关系的分布式

Hibernate: insert into department (department_code, department_name) values (?, ?)
Hibernate: insert into employee (department_department_id, employee_code, employee_name) values (?, ?, ?)
Hibernate: insert into employee (department_department_id, employee_code, employee_name) values (?, ?, ?)

3.关闭子对象中的父对象toString,避免无限循环调用ui

4、双向关系使用code关联

同单向关系相似,且有额外的update操做
code关联,使用JoinColumn时不可同时使用mappedByspa

5、级联操做设置

  • CascadeType.PERSIST:级联保存,在保存department的同时保存employee对象
  • CascadeType.MERGE:级联更新,将department和employee视为一个总体,任何一个对象有变化,都会更新
  • CascadeType.REMOVE:级联删除设计

    • 当没有设置时,delete主对象时,子对象只是去掉关系;remove子对象时也只是去掉关系,若是增长orphanRemoval = true则会删除remove的子对象
    • 当有设置时,delete主对象时,子对象一样会被删除
  • CascadeType.REFRESH:级联刷新(较少使用),在并发的场景下避免脏数据
  • CascadeType.DETACH:级联脱管(较少使用)
  • CascadeType.ALL:以上所有,须要根据实际状况谨慎设置,以避免产生混乱

6、源代码

https://gitee.com/hypier/barr...

此处输入图片的描述

相关文章
相关标签/搜索