以下将讲解关系型数据的关系描述。仅仅是作为总结。
主要针对 JPA 进行详解
关于关系型数据库的关系
关系的概念(Relationship)
角色 (Roles)
现实中的人称关系,有你、我、她、他、它、你们、我们、她们、她们和它们,而在数据库中的两个实体的关系通俗的将有这边儿、对面以及两边。
Student --- Course
方向性 (Directoionality)
实体中关系的方向性主要有两种,一种是双向关系,另一种则是单向关系。
双向 (bidirectional)
Student <---> Course
单向 (unidirectional)
Student ---> LoginLog
当然双向关系的可以拆分为两个单向关系。
源(Source) 目标 (Target)
Student ---> Course
目标(Target) 源 (Source)
Student <--- Course
基数 (Cardinality)
在关系中的每一个角色都会有独自的基数。
LoginLog *--->1 Student
单向“多对一” (many-to-one)关系
这里学生的基数是 1(一个登录日志仅仅只属于某一个学生,所以学生属于 one 一边),而登录日志的基数用"*"标识(一个学生可以有多个登录日志,登录日志属于 many 一边)。
Student *<--->* Course
双向“多对多” (many-to-many)关系
序数 (Ordinality)
当源(Source)实体完成创建后,目标(Target)实体是否需要被指定就靠序数来决定,一般用 0 或者 1 标识。
映射 (Mappings)
数据映射主要有一下四种:
- 多对一 (Many-to-one)
- 一对一 (One-to-one)
- 一对多 (One-to-Many)
- 多对多 (Many-to-Many)
从整体上也分为:
- 单值关联 (Single-Valued Associations)
- 集合值关联 (Collection-Valued Associations)
单值关联 (Single-Valued Associations)
如果关系中目标实体的基数为 1,这种就成为单值联系。如“多对一”和“一对一”。
多对一 (Many-to-one)
LoingLog *--->1 Student
表结构如下:
create table login_logs (
id long primary key,
log_ip int,
log_at timestamp,
stu_id int,
foreign key(stu_id) references students(id)
);
create table students (
id int primary key,
name varchar(20)
);
用 JPA 表示如下:
@Entity
public class LoginLog {
// ...
@ManyToOne
private Student student;
// ...
}
使用 Join Columns
@Entity
public class LoginLog {
@Id private long id
@ManyToOne
@JoinColumn(name = "stu_id")
private Student student;
// ...
}
一对一 (One-to-one)
Student 1--->0..1 StudentProfiles
表结构如下:
create table students (
id int primary key,
name varchar(20)
);
create table student_profiles (
id int primary key,
gender tinyint,
stu_id int,
foreign key(stu_id) references students(id)
);
用 JPA 表示如下:
@Entity
public class StudentProfile {
@Id private int id;
@OneToOne
@JoinColumn(name = "stu_id")
private Student student;
}
@Entity
public class Student {
@Id private int id;
@OneToOne(mappedBy = "student")
private StudentProfile profile;
// ...
}
集合值关联 (Collection-Valued Associations)
一对多和多对多关系中都有一个共同点就是都有多个 (many) 目标实体,这样的关联就称之为集合值关联。
一对多 (One-to-Many)
Student 1--->* LoginLog
表结构在这里就不再赘述。
@Entity
public class Student {
@Id private int id;
@OneToMany(mappedBy = "student")
private Collection<LoginLog> logs;
}
也可以使用 targetEntity 来指定集合中元素类型。
@Entity
public class Student {
@Id private int id
@OneToMany(targetEntity = LoginLog.class, mappedBy = "student")
private Collection logs;
}
多对多 (Many-to-Many)
Student *<--->* Course
双向关系
表结构如下:
create table students (
id int primary key,
name varchar(20)
);
create table courses (
id int primary key,
name varchar(50)
);
@Entity
public class Student {
@Id private int id;
@ManyToMany
private Collection<Course> courses;
// ...
}
@Entity
public class Course {
@Id private int id;
@ManyToMany(mappedBy = "courses")
private Collection<Student> students;
// ...
}
create table records (
stu_id int,
crs_id int,
primary key (stu_id, crs_id),
foreign key (stu_id) references students(id),
foreign key (crs_id) references courses(id)
);
使用 Join Tables
@Entity
public class Student {
@Id private int id;
@ManyToMany
@JoinTable(name = "records",
joinColumns = @JoinColumn(name = "stu_id"),
inverseJoinColumns = @JoinColumn(name = "crs_id"))
private Collection<Course> courses;
}
关系还需亲自理清,所以建议读者自己动手理一下,效果会更好。
References
Pro JPA 2 in Java EE 8, 3rd Edition. Mike Keith, Merrick Schincariol, Massimo Nardone. 2018.