推荐链接:
总结——》【Java】
总结——》【Mysql】
总结——》【Redis】
总结——》【Kafka】
总结——》【Spring】
总结——》【SpringBoot】
总结——》【MyBatis、MyBatis-Plus】
总结——》【Linux】
总结——》【MongoDB】
总结——》【Elasticsearch】
SpringBoot——》关联映射
- 一、场景
- 二、关联映射
- 1、@OneToOne(一对一)
- 实现一:@JoinColumn
- 实现二:@PrimaryKeyJoinColumn
- 实现三:不使用@JoinColumn和@PrimaryKeyJoinColumn
- 2、@OneToMany(一对多)
- 实现一:@JoinColumn
- 实现二:@JoinTable
- 实现三:不使用@JoinColumn
- 3、@ManyToOne(多对一)
- 实现一:@JoinColumn
- 4、@ManyToMany(多对多)
- 实现一:@JoinTable
- 三、完整示例
- 1、员工实体类:Employee.java
- 2、地址实体类:Address.java
- 3、部门实体类:Department.java
- 4、角色实体类:Role.java
一、场景
以员工、地址、部门、角色四者之间的关联关系为例:
- 一个员工只能有一个地址,一个地址也只属于一个员工;
- 一个员工只能属于一个部门,但是一个部门可以包含有多个员工;
- 一个员工可以拥有多个角色,一个角色也可以属于多个员工。
表 | 实体类 | 描述 | 备注 |
---|---|---|---|
tb_employee | Employee | 员工 | 一个员工只能有一个地址 一个员工只能属于一个部门 一个员工可以拥有多个角色 |
tb_address | Address | 地址 | 一个地址只属于一个员工 |
tb_department | Department | 部门 | 一个部门可以包含有多个员工 |
tb_role | Role | 角色 | 一个角色也可以属于多个员工 |
二、关联映射
由于 @OneToOne(一对一)、@OneToMany(一对多)、@ManyToOne(多对一)、@ManyToMany(多对多) 等注解只能确定实体之间几对几的关联关系,它们并不能指定与实体相对应的数据库表中的关联字段,因此,需要与 @JoinColumn 注解来配合使用。
1、@OneToOne(一对一)
实现一:@JoinColumn
在员工表中会有一个指向地址表主键的字段address_id
// 一个员工只能有一个地址,在员工实体类中添加如下注解:@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "address_id")
private Address address;
实现二:@PrimaryKeyJoinColumn
如果员工表和地址表是以主键关联的:
- 员工表主键:employee_id
- 地址表主键:address_id
// 一个员工只能有一个地址,在员工实体类中添加如下注解:@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@PrimaryKeyJoinColumn(name = "employee_id", referencedColumnName = "address_id")
private Address address;
实现三:不使用@JoinColumn和@PrimaryKeyJoinColumn
Hibernate会自动在员工表生成关联字段,字段默认的命名规则:被控方类名_被控方主键,如:address_id
// 一个员工只能有一个地址,在员工实体类中添加如下注解:@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
// Hibernate会自动在员工表生成关联字段,字段默认的命名规则:被控方类名_被控方主键,如:address_id
private Address address;
2、@OneToMany(一对多)
一个员工只能属于一个部门,但是一个部门可以包含有多个员工,如果我们站在部门的角度来看,部门与员工之间就是一对多的关系。
实现一:@JoinColumn
// 一个部门可以包含有多个员工,在部门实体类中添加如下注解:@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "department_id")
private List<Employee> employees;
实现二:@JoinTable
// 一个部门可以包含有多个员工,在部门实体类中添加如下注解:@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
/**
* joinColumns 用来指定中间表中关联自己ID的字段
* inverseJoinColumns 用来指定中间表中关联对方ID的字段
*/
@JoinTable(name = "tbl_employee_department", joinColumns = {
@JoinColumn(name = "department_id") }, inverseJoinColumns = { @JoinColumn(name = "employee_id") })
private List<Employee> employees;
实现三:不使用@JoinColumn
Hibernate会自动生成一张中间表来对员工和部门进行绑定,表名默认的命名规则:一的表名_一实体类中关联多的属性名,例如,部门表名为 tb_department ,部门实体中关联的员工集合属性名为 employees ,则生成的中间表名为:tb_department_employees。
通常并不推荐让Hibernate自动去自动生成中间表,而是使用@JoinTable注解来指定中间表。
3、@ManyToOne(多对一)
实现一:@JoinColumn
// 一个部门可以包含有多个员工,但一个员工只能属于一个部门,在员工实体类中添加如下注解:@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "department_id")
private Department department;
4、@ManyToMany(多对多)
一个员工可以拥有多个角色,一个角色也可以属于多个员工,员工与角色之间就是多对多的关系。通常这种多对多关系都是通过创建中间表来进行关联处理,并使用@JoinTable注解来指定。
实现一:@JoinTable
// 一个员工可以拥有多个角色,在员工实体类中添加如下注解:@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinTable(name = "tb_employee_role", joinColumns = { @JoinColumn(name = "employee_id") }, inverseJoinColumns = {
@JoinColumn(name = "role_id") })
private List<Role> roles;
// 一个角色可以属于多个员工,在角色实体类中添加如下注解:@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinTable(name = "tb_employee_role", joinColumns = { @JoinColumn(name = "role_id") }, inverseJoinColumns = {@JoinColumn(name = "employee_id") })
private List<Employee> employees;
三、完整示例
1、员工实体类:Employee.java
@Entity
@Table(name = "tb_employee")
@Comment("员工")
@Data
public class Employee {@Id@GeneratedValue(generator = "seq_employee_id")@SequenceGenerator(name = "seq_employee_id", sequenceName = "seq_employee_id")private Long id;@Column(name = "name", columnDefinition = "varchar(64) COMMENT '名称'", nullable = false)private String name;@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)@JoinColumn(name = "address_id", columnDefinition = "bigint(20) COMMENT '地址ID'", nullable = false)// @PrimaryKeyJoinColumn(name = "employee_id", referencedColumnName = "address_id")private Address address;@Getter@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)@JoinColumn(name = "department_id")private Department department;@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)@JoinTable(name = "tb_employee_role",joinColumns = {@JoinColumn(name = "employee_id")},inverseJoinColumns = {@JoinColumn(name = "role_id")})private List<Role> roles; // 角色
}
2、地址实体类:Address.java
@Entity
@Table(name = "tb_address")
@Comment("地址")
@Data
public class Address {@Id@GeneratedValue(generator = "seq_address_id")@SequenceGenerator(name = "seq_address_id", sequenceName = "seq_address_id")private Long id;@Column(name = "address", columnDefinition = "varchar(64) COMMENT '地址'", nullable = false)private String address;
}
3、部门实体类:Department.java
@Entity
@Table(name = "tb_department")
@Comment("部门")
@Data
public class Department {@Id@GeneratedValue(generator = "seq_department_id")@SequenceGenerator(name = "seq_department_id", sequenceName = "seq_department_id")private Long id;@Getter@Column(name = "name", columnDefinition = "varchar(64) COMMENT '名称'", nullable = false)private String name;@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)@JoinColumn(name = "department_id")/*** joinColumns 用来指定中间表中关联自己ID的字段* inverseJoinColumns 用来指定中间表中关联对方ID的字段*/
// @JoinTable(name = "tb_employee_department",
// joinColumns = {@JoinColumn(name = "department_id", referencedColumnName = "id")},
// inverseJoinColumns = {@JoinColumn(name = "employee_id", referencedColumnName = "id")})private List<Employee> employees;
}
4、角色实体类:Role.java
@Entity
@Table(name = "tb_role")
@Comment("角色")
@Data
public class Role {@Id@GeneratedValue(generator = "seq_role_id")@SequenceGenerator(name = "seq_role_id", sequenceName = "seq_role_id")private Long id;@Column(name = "name", columnDefinition = "varchar(64) COMMENT '名称'", nullable = false)private String name;@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)@JoinTable(name = "tb_employee_role",joinColumns = {@JoinColumn(name = "role_id")},inverseJoinColumns = {@JoinColumn(name = "employee_id")})private List<Employee> employees; // 拥有角色的员工
}