JPA+MySQL详解
首先明确两个端的关联关系,在java实体类定义中,含有mappedBy属性的时关系被维护端,含有关联字段的是关系维护端。
一、OneToOne关联关系
假设有实体People和Address,他们的关系是一对一,再设定People实体是关系的维护端,应有如下设计
//People.java
@Entity
@Table(name = "people")
public class People {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Long id;//id
@Column(name = "\"name\"", nullable = true, length = 20)//这个name加上双引号的原因是在jpa转为sql的时候会把name识别成sql关键字导致报错,反斜杠用来转义
private String name;//姓名
@OneToOne(cascade=CascadeType.ALL)//People是关系的维护端,当对People对象进行增删改时,会同时对address对象进行增删改
@JoinColumn(name = "address_id", referencedColumnName = "id")//people中的address_id字段参考address表中的id字段
private Address address;//地址
//getter and setter
}
//Address.java
@Entity
@Table(name = "address")
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Long id;//id
@Column(name = "location", nullable = true, length = 100)
private String location;//位置
@OneToOne(mappedBy = "address")//这里没有级联操作,不需要维护关系
private People people;
//getter and setter
}
二、OneToMany/ManyToOne关联关系
在一对多关系中,“一”的一端是关系被维护端,它含有“多”的一端的对象集合属性,用@OneToMany注释这个属性;“多”的一端是关系维护端,它含有“一”的一端的对象属性,用@ManyToOne注释这个属性。
假设有实体User和Department,他们的关系是多对一的关系,有如下设计
//User.java
@Entity
@Table(name = "user")
public class UserEntity {
@GenericGenerator(name = "uuid", strategy = "uuid")
@GeneratedValue(generator = "uuid")
@Id
private String id;
@Column(name = "\"name\"")
private String name;
@JoinColumn(name = "department_id", referencedColumnName = "id")
@ManyToOne(cascade = {CascadeType.MERGE, CascadeType.REFRESH}, optional = false)//一般需要级联合并和刷新,具体结合业务需求,optional=false表示department不可为空
private SabDepartmentEntity department;
//getter and setter
}
//Department.java
@Entity
@Table(name = "department")
public class DepartmentEntity {
@GenericGenerator(name = "uuid", strategy = "uuid")
@GeneratedValue(generator = "uuid")
@Id
private String id;
@Column(name = "\"name\"")
private String name;
@OneToMany(mappedBy = "department", fetch = FetchType.LAZY, cascade = CascadeType.ALL)//这里需要所有级联操作,具体可以结合业务需求
private List<SabUserEntity> users;
//getter and setter
}
三、ManyToMany关联关系
多对多的关联关系中一般不设置级联操作,根据需求来决定任意一方为关系维护端,关系维护端的属性仍然有关联字段的声明,关系被维护端仍然有mappedBy的声明。值得注意的是,关系被维护端并不能直接删除对象,如果需要删除,需要先将其对应的关系维护端中的关系删除,比如有用户和角色,用户是关系维护端,如果要删除角色,需要先将对应的用户的角色列表中这个角色清除,才能删除角色。而关系维护端可以直接删除,假如设置了级联删除,举个例子,删除用户时也会删除角色。一般关联关系表使用的是两个外键作为双主键。
//User.java
@Entity
@Table(name = "user")
public class userEntity {
@GenericGenerator(name = "uuid", strategy = "uuid")
@GeneratedValue(generator = "uuid")
@Id
private String id;
@Column(name = "\"name\"")
private String name;
@JoinTable(name = "sab_user_role_rel",
joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")},
inverseJoinColumns = {@JoinColumn(name = "role_id", referencedColumnName = "id")}
)//这个joinColumns的JoinColumn的name是当前实体在关联关系中的外键列,inverseJoinColumns的JoinColumn的name是对方实体在关联关系中的外键列,referencedColumnName是指该实体在本身实体中的主键列
@ManyToMany
private List<SabRoleEntity> roles;
//getter and setter
}
//Role.java
@Entity
@Table(name = "role")
public class RoleEntity {
@GenericGenerator(name = "uuid", strategy = "uuid")
@GeneratedValue(generator = "uuid")
@Id
private String id;
@Column(name = "\"name\"")
private String name;
@ManyToMany(mappedBy = "roles", fetch = FetchType.LAZY)
private List<SabUserEntity> users;
//getter and setter
}
另外附上级联操作作用的解析
jpa级联操作Cascade解析