Hibernate关系映射的主要任务是实现数据库关系表与持久化类之间的映射。
1.一对一关联
有两种实现方式:共享主键方式(使两个数据表的主键使用相同的值,通过主键形成一对一映射关系)和唯一外键方式(一个表的外键与另一个表的唯一主键对应形成一对一映射关系)。
1)共享主键方式
在注册某个论坛会员的时候,往往不但要填写登录账号和密码,还要填写其他的详细信息,这两部分信息通常会放在不同的表中,如表4.1、表4.2所示。
字 段 名 称 | 数 据 类 型 | 主 键 | 自 增 | 允 许 为 空 | 描 述 |
ID | int(4) | 是 | ID号 | ||
USERNAME | varchar(20) | 登录账号 | |||
PASSWORD | varchar(20) | 登录密码 |
表4.1 登录表Login
字 段 名 称 | 数 据 类 型 | 主 键 | 自 增 | 允 许 为 空 | 描 述 |
ID | int(4) | 是 | 增1 | ID号 | |
TRUENAME | varchar(8) | 是 | 真实姓名 | ||
varchar(50) | 是 | 电子邮件 |
表4.2 详细信息表Detail
登录表和详细信息表属于典型的一对一关联关系,可按共享主键方式进行。步骤如下:
(1) 创建Java项目,命名为“Hibernate_mapping”。
(2)添加Hibernate开发能力,步骤同。HibernateSessionFactory类同样位于org.util包下。(注意先要配置数据库连接)
(3)编写生成数据库表对应的Java类对象和映射文件。(注意放置的位置:选对项目名)
a)Login表对应的POJO类Login.java:
package org.model;public class Login implements java.io.Serializable{ private int id; // ID号 private String username; // 登录账号 private String password; // 密码 private Detail detail; // 详细信息 // 省略上述各属性的getter和setter方法}
b)Detail表对应的Detail.java:
package org.model;public class Detail implements java.io.Serializable{ private int id; // ID号 private String trueName; // 真实姓名 private String email; // 电子邮件 private Login login; // 登录信息 // 省略上述各属性的getter和setter方法}
c)Login表与Login类的ORM映射文件Login.hbm.xml。
detail
d)Detail表与Detail类的ORM映射文件Detail.hbm.xml:
(4)在hibernate.cfg.xml文件中加入配置映射文件的语句。
(5)创建测试类。 在src文件夹下创建包test,在该包下建立测试类,命名为“Test.java”。其代码。
package test; import java.util.List;import org.hibernate.Query;import org.hibernate.Session;import org.hibernate.Transaction;import org.model.*;import org.util.HibernateSessionFactory;import java.sql.*; public class Test { public static void main(String[] args) { // 调用HibernateSessionFactory的getSession方法创建Session对象 Session session = HibernateSessionFactory.getSession(); // 创建事务对象 Transaction ts = session.beginTransaction(); Detail detail = new Detail(); Login login = new Login(); login.setUsername("yanhong"); login.setPassword("123"); detail.setTrueName("严红"); detail.setEmail("yanhong@126.com"); // 相互设置关联 login.setDetail(detail); detail.setLogin(login); // 这样完成后就可以通过Session对象调用session.save(detail)来持久化该对象 session.save(detail); ts.commit(); HibernateSessionFactory.closeSession(); }}
(6) 运行程序,测试结果。 因为该程序为Java Application,所以可以直接运行。在完全没有操作数据库的情况下,程序就完成了对数据的插入。插入数据后,Login表和Detail表的内容如图4.12、图4.13所示。
图4.12 Login表
图4.13 Detail表
2)唯一外键方式
唯一外键的情况很多,例如,每个人对应一个房间。其实在很多情况下,可以是几个人住在同一个房间里面,就是多对一的关系。但是如果把这个多变成唯一,也就是说让一个人住一个房间,就变成了一对一的关系了,这就是前面说的一对一的关系其实是多对一关联关系的一种特殊情况。对应的Person表和Room表如表4.3、表4.4所示。
字 段 名 称 | 数 据 类 型 | 主 键 | 自 增 | 允 许 为 空 | 描 述 |
Id | int | 是 | 增1 | ID号 | |
name | varchar(20) | 姓名 | |||
room_id | int | 是 | 房间号 |
表4.3 Person表
字 段 名 称 | 数 据 类 型 | 主 键 | 自 增 | 允 许 为 空 | 描 述 |
id | int(4) | 是 | 增1 | ID号 | |
address | varchar(100) | 地址 |
表4.4 Room表
步骤如下:
(1)在项目Hibernate_mapping的org.model包下编写生成数据库表对应的Java类对象和映射文件。
Person表对应的POJO类Person.java:
package org.model;public class Person implements java.io.Serializable { private Integer id; private String name; private Room room; // 省略上述各属性的getter和setter方法}
Room表对应的POJO类Room.java:
package org.model;public class Room implements java.io.Serializable{ private int id; private String address; private Person person; // 省略上述各属性的getter和setter方法}
Person表与Person类的ORM映射文件Person.hbm.xml:
去掉roomId的配置:
Room表与Room类的ORM映射文件Room.hbm.xml:
(2)在hibernate.cfg.xml文件中加入如下的配置映射文件的语句。
(3)编写测试代码。
在src文件夹下的包test的Test类中加入如下代码:
Person person=new Person();person.setName("liumin");Room room=new Room();room.setAddress("NJ-S1-328");person.setRoom(room);session.save(person);
(4)运行程序,测试结果。
因为该程序为Java Application,所以可以直接运行。在完全没有操作数据库的情况下,程序就完成了对数据的插入。插入数据后,Person表和Room表的内容如图4.14、图4.15所示。
图4.14 Person表
图4.15 Room表
2.多对一单向关联
只要把上例中的一对一的唯一外键关联实例稍微修改就可以变成多对一。步骤如下:
(1)在项目Hibernate_mapping的org.model包下编写生成数据库表对应的Java类对象和映射文件。
其对应表不变,Person表对应的类也不变,对应的Person.hbm.xml文件修改如下(只是去掉 <many-to-one/>中的unique="true"):
而Room表不变,对应的POJO类如下:(去掉private Person person及其方法;)
package org.model;public class Room implements java.io.Serializable{ private int id; private String address; // 省略上述各属性的getter和setter方法}
Room表与Room类的ORM映射文件Room.hbm.xml如下(去掉<one-to-one/>配置):
因为是单向多对一,所以无需在“一”的一边指定“多”的一边。(好比一班学生可以记住一个老师,这个老师记不住每个学生)
(2)编写测试代码。
在src文件夹下的包test的Test类中加入如下代码(跟上例一样,可以修改一下数据):
Person person=new Person();person.setName("liuyanmin");Room room=new Room();room.setAddress("NJ-S1-328");person.setRoom(room);session.save(person);
(3) 运行程序,测试结果。
因为该程序为Java Application,所以可以直接运行。在完全没有操作数据库的情况下,程序就完成了对数据的插入。插入数据后,Person表和Room表的内容如图4.16、图4.17所示。
图4.16 Person表
图4.17 Room表
3.一对多双向关联
多对一单向关联,“一”的一方也知道“多”的一方,就变成了一对多(或多对一)双向关联。下面通过修改4.3.2节的例子来完成双向多对一的实现。步骤如下:
(1) 在项目Hibernate_mapping的org.model包下编写生成数据库表对应的Java类对象和映射文件。
Person表对应的POJO及其映射文件不用改变,现在来修改Room表对应的POJO类及其映射文件。对应的POJO类Room.java。
package org.model;import java.util.HashSet;import java.util.Set;public class Room { private int id; private String address; private Set person=new HashSet(); //集合,存放多个Person对象 public int getId() { return id; } public void setId(int id) { this.id=id; } public String getAddress() { return address; } public void setAddress(String address) { this.address=address; } public Set getPerson() { return person; } public void setPerson(Set person) { this.person=person; }}
Room表与Room类的ORM映射文件Room.hbm.xml。
该配置文件中cascade配置的是级联程度,它有以下几种取值:
all:表示所有操作句在关联层级上进行连锁操作。
save-update:表示只有save和update操作进行连锁操作。
delete:表示只有delete操作进行连锁操作。
all-delete-orphan:在删除当前持久化对象时,它相当于delete;在保存或更新当前持久化对象时,它相当于save-update。另外它还可以删除与当前持久化对象断开关联关系的其他持久化对象。
(2)编写测试代码。在src文件夹下的包test的Test类中加入如下代码:
Person person1=new Person();Person person2=new Person();Room room=new Room();room.setAddress("NJ-S1-328");person1.setName("李方方");person2.setName("王艳");person1.setRoom(room);person2.setRoom(room);//这样完成后就可以通过Session对象调用session.save(person1)和session.save(person)会自动保存roomsession.save(person1);session.save(person2);
(3)运行程序,测试结果。 因为该程序为Java Application,所以可以直接运行。在完全没有操作数据库的情况下,程序就完成了对数据的插入。插入数据后,Person表和Room表的内容如图4.18、图4.19所示。
图4.18 Person表
图4.19 Room表
由于是双向的,当然也可以从Room的一方来保存Person,在Test.java中加入如下代码:
Person person1=new Person();Person person2=new Person();Room room=new Room();room.setAddress("NJ-S1-328");person1.setName("李方方");person2.setName("王艳");Set persons=new HashSet();persons.add(person1);persons.add(person2);room.setPerson(persons);//这样完成后,就可以通过Session对象调用session.save(room)会自动保存person1和person2session.save(room);
运行程序,插入数据后,Person表和Room表的内容如图4.20、图4.21所示。
图4.20 Person表
图4.21 Room表
4.多对多关联
1)多对多单向关联
学生和课程就是多对多的关系,一个学生可以选择多门课程,而一门课程又可以被多个学生选择。多对多关系在关系数据库中不能直接实现,还必须依赖一张连接表。如表4.6、表4.7和表4.8所示。
字 段 名 称 | 数 据 类 型 | 主 键 | 自 增 | 允 许 为 空 | 描 述 |
ID | int | 是 | 增1 | ID号 | |
SNUMBER | varchar(10) | 学号 | |||
SNAME | varchar(10) | 是 | 姓名 | ||
SAGE | int | 是 | 年龄 |
表4.6 学生表student
字 段 名 称 | 数 据 类 型 | 主 键 | 自 增 | 允 许 为 空 | 描 述 |
ID | int | 是 | 增1 | ID号 | |
CNUMBER | varchar(10) | 课程号 | |||
CNAME | varchar(20) | 是 | 课程名 |
表4.7 课程表course
字 段 名 称 | 数 据 类 型 | 主 键 | 自 增 | 允 许 为 空 | 描 述 |
SID | int | 是 | 学生ID号 | ||
CID | int | 是 | 课程ID号 |
表4.8 连接表stu_cour
由于是单向的,也就是说从一方可以知道另一方,反之不行。这里以从学生知道选择了哪些课程为例实现多对多单向关联。步骤如下:
(1)在项目Hibernate_mapping的org.model包下编写生成数据库表对应的Java类对象和映射文件。student表对应的POJO类如下:
package org.model;import java.util.HashSet;import java.util.Set; public class Student implements java.io.Serializable{private int id;private String snumber;private String sname;private int sage;private Set courses=new HashSet(); //省略上述各属性的getter和setter方法}
student表与Student类的ORM映射文件Student.hbm.xml。
// 级联程度 // 指定参照student表的外键名称 // 指定参照course表的外键名称
course表对应的POJO如下:
package org.model;public class Course implements java.io.Serializable{private int id; private String cnumber; private String cname; //省略上述各属性的getter和setter方法。}
course表与Course类的ORM映射文件Course.hbm.xml。
(2)在hibernate.cfg.xml文件中加入如下的配置映射文件的语句。
(3)编写测试代码。在src文件夹下的包test的Test类中加入如下代码。
Course cour1=new Course();Course cour2=new Course();Course cour3=new Course();cour1.setCnumber("101");cour1.setCname("计算机基础");cour2.setCnumber("102");cour2.setCname("数据库原理");cour3.setCnumber("103");cour3.setCname("计算机原理");Set courses=new HashSet();courses.add(cour1);courses.add(cour2);courses.add(cour3);Student stu=new Student();stu.setSnumber("081101");stu.setSname("李方方");stu.setSage(21);stu.setCourses(courses);session.save(stu);//设置完成后就可以通过Session对象调用session.save(stu)完成持久化
(4) 运行程序,测试结果。 因为该程序为Java Application,所以可以直接运行。在完全没有操作数据库的情况下,程序就完成了对数据的插入。插入数据后,student表、course表及连接表stu_cour表的内容如图4.22、图4.23、图4.24所示。
图4.22 student表
图4.23 course表
图4.24 stu_cour表
2)多对多双向关联
同时实现 两个互逆的多对多单项关联即可。 首先将其Course表所对应的POJO对象修改成如下代码:
package org.model;import java.util.HashSet;import java.util.Set;public class Course implements java.io.Serializable{ private int id; private String cnumber; private String cname; private Set stus=new HashSet(); //省略上述各属性的getter和setter方法}
Course表与Course类的ORM映射文件Course.hbm.xml:
// 级联操作为所有 // 指定参照course表的外键名称 // 指定参照student表的外键名称
实际用法与多对多单项关联相同,只是主控方不同而已。
附:目录