Hibernate–3
学习大纲:
数据库中表的关系
一对一
一对多
多对多
注意:不管是哪种关系,在逻辑上都有主表和从表之分
外键 : 从表中的一列来源于主表的主键,或者为null,默认情况下外键是可以重复的
如何确立和实现表之间的关系
确立:看表的外键90%的情况下能确立表之间的关系
实现:
一对一 (A表和B表):
- B表中的外键是A表的主键,且此外键设置唯一约束,非空约束
- B表的外键是A表的主键,同时又是主键
一对多(A表和B表):
其中A表示主表,B表示从表,主表一般指的是一,从表指的是多
B表的外键是A表的主键,也可以为null
多对多(A表和B表)
维护一个第三表,该表只有两个字段,且都为主键,引用自A,B两个表的主键
任何一个多表和第三表之间的关系都是一对多的关系
使用Hibernate多表映射配置的步骤
- 第一步:确立两张表之间的关系
- 第二步:在数据库中创建出这两张表,并实现两张表之间的关系
- 第三步:在实体类中描述出两个实体之间的关系
- 第四步:在映射配置文件中配置两张表之间的关系
情景一:建立房东(landlord)数据表和租户(tenant)数据表
第一步:确立两张表之间的关系
一个房东可以有多个租户
一个租户只能有一个房东
所以房东和租户之间是一对多的关系
第二步:在数据库中创建出这两张表,并实现两张表之间的关系
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18/*房东信息表*/
CREATE TABLE hb_landlord(
l_id INT PRIMARY KEY AUTO_INCREMENT,
l_name VARCHAR(10),
l_sex CHAR(1),
l_age INT(3),
l_phone VARCHAR(15)
)
/*租户信息表*/
CREATE TABLE hb_tenant(
t_id INT PRIMARY KEY AUTO_INCREMENT,
t_name VARCHAR(10),
t_sex CHAR(1),
t_age INT(3),
t_phone VARCHAR(15),
t_job VARCHAR(10)
)只要在Hibernate中配置好表的映射配置文件以后,获取Session的时候,会自动加载配置文件,Hibernate检查表是否已经创建,如果没有创建就替我们创建表
第三步:在实体类中描述出两个实体之间的关系
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75// 房东 表
public class Landlord {
private Integer lid;
private String lname;
private String lsex;
private Integer lage;
private String lphone;
// 一位房东可以包含多位租客,建立一对多关系
// 注意这里的处理方式:防止后面调用添加租客的时候报空指针异常(set还没有创建),提前将其创建出来
// 如果数据众多的时候,会有多个tenants创建,会很占用内存,所以初始化的时候现将其初始容量设置成0
private Set<Tenant> tenants = new HashSet<>(0);
public Landlord() {
}
public Set<Tenant> getTenants() {
return tenants;
}
public void setTenants(Set<Tenant> tenants) {
this.tenants = tenants;
}
public Integer getLid() {
return lid;
}
public void setLid(Integer lid) {
this.lid = lid;
}
public String getLname() {
return lname;
}
public void setLname(String lname) {
this.lname = lname;
}
public String getLsex() {
return lsex;
}
public void setLsex(String lsex) {
this.lsex = lsex;
}
public Integer getLage() {
return lage;
}
public void setLage(Integer lage) {
this.lage = lage;
}
public String getLphone() {
return lphone;
}
public void setLphone(String lphone) {
this.lphone = lphone;
}
public String toString() {
return "Landlord{" +
"lid=" + lid +
", lname='" + lname + '\'' +
", lsex='" + lsex + '\'' +
", lage=" + lage +
", lphone='" + lphone + '\'' +
'}';
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75//租户 表
public class Tenant {
private Integer tid;
private String tname;
private String tsex;
private Integer tage;
private String tphone;
private String tjob; // 从事的工作
// 一位租户只能有一个房东,建立关系
private Landlord landlord;
public Tenant() {
}
public Integer getTid() {
return tid;
}
public void setTid(Integer tid) {
this.tid = tid;
}
public String getTname() {
return tname;
}
public void setTname(String tname) {
this.tname = tname;
}
public String getTsex() {
return tsex;
}
public void setTsex(String tsex) {
this.tsex = tsex;
}
public Integer getTage() {
return tage;
}
public void setTage(Integer tage) {
this.tage = tage;
}
public String getTphone() {
return tphone;
}
public void setTphone(String tphone) {
this.tphone = tphone;
}
public String getTjob() {
return tjob;
}
public void setTjob(String tjob) {
this.tjob = tjob;
}
public String toString() {
return "Tenant{" +
"tid=" + tid +
", tname='" + tname + '\'' +
", tsex='" + tsex + '\'' +
", tage=" + tage +
", tphone='" + tphone + '\'' +
", tjob='" + tjob + '\'' +
'}';
}
}
第四步:在映射配置文件中配置两张表之间的关系
1 | <?xml version="1.0" encoding="UTF-8" ?> |
1 | <?xml version="1.0" encoding="UTF-8" ?> |
情景二:学生和老师的信息
第一步:确立两张表之间的关系
一位学生可以拥有多个老师
一位老师可以拥有多个学生
所以学生表和老师表是多对多的关系
第二步:在数据库中创建出这两张表,并实现两张表之间的关系
只要配置文件中没有出错,Hibernate就会创建出正确的表来
第三步:在实体类中描述出两个实体之间的关系
互相持有对方的一个Set集合引用
第四步:在映射配置文件中配置两张表之间的关系
Student实体对应的数据库表
1
2
3
4
5
6
7
8
9
10
11
12
13
14<?xml version="1.0" encoding="UTF-8" ?>
<!--指定命名空间,从hibernate-core-5.2.16.Final包中找-->
<hibernate-mapping package="com.lee.many2many">
<class name="Student" table="hb_student">
<id name="sid" column="s_id">
<!--主键自增长,使用数据库本地的自增长能力-->
<generator class="native"></generator>
</id>
<property name="sname" column="s_name"></property>
<property name="sage" column="s_age"></property><!-- set:用于配置映射的集合属性 name:指定当前映射实体类中对应集合属性的属性名称 table:指定生成中间表的表名 column:当前映射文件对应实体在中间表中的联合主键字段 class:指定集合属性所装的实体类型 column:指定对方在表中对应的字段名称 --> <!--注意:多对多情况下慎用级联删除,可能会出现删除不需要删除的对象--> <set name="teachers" table="tea_stu_ref" cascade="save-update,delete"> <key column="stu_id"></key> <many-to-many class="Teacher" column="tea_id"></many-to-many> </set> <!-- 理解 : 因为维护了多的一方的集合,肯定要知道多的一方对应的实体类(!!必须配置实体类名) : 多的一方怎么跟我建立起关系的呢?因为它引用了我的主键作为它的外键(!!必须要知道外键对应的字段) : 因为已经指定了实体类,而实体类已经通过映射配置文件为其配置了对应的表名,因此表名可有可无 --> </class>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Teacher实体对应的数据库表
```xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.lee.many2many">
<class name="Teacher" table="hb_teacher">
<id name="tid" column="t_id">
<generator class="native"></generator>
</id>
<property name="tname" column="t_name"></property>
<property name="tage" column="t_sex"></property>
<!--注意:多对多情况下慎用级联删除,可能会出现删除不需要删除的对象-->
<set name="students" table="tea_stu_ref">
<key column="tea_id"></key>
<many-to-many class="Student" column="stu_id"></many-to-many>
</set>
<!--
理解 : 因为维护了多的一方的集合,肯定要知道多的一方对应的实体类(!!必须配置实体类名)
: 多的一方怎么跟我建立起关系的呢?因为它引用了我的主键作为它的外键(!!必须要知道外键对应的字段)
: 因为已经指定了实体类,而实体类已经通过映射配置文件为其配置了对应的表名,因此表名可有可无
-->
</class>
</hibernate-mapping>
延迟加载思想
导航查询思想
load方法和get方法的区别,get方法立即查询.get方法取决于当前实体类映射配置文件中
<calss>标签中的lazy属性,true表示延迟加载.