系列文章目录
Hibernate框架【三】——基本映射——一对一映射
基本映射——多对一和一对多映射
- 系列文章目录
- 前言
- 一、多对一映射是什么?
- 1.案例:现在有两个实体User实体和Group,其中多个User属于一个Group,表现出多对一的关系。
- ①.实体结构
- ②.实体对象的xml配置
- ③.什么是级联?
- ④.生成的表结构
- ⑤.往表中插入数据
- ⑥.查询数据
- 二、一对多映射是什么?
- 1.案例:现在有两个实体Classes实体和Student,其中一个班级包含多个学生,表现出一对多的关系。
- ①实体结构
- ②.实体对应的xml配置
- ③.生成的表结构
- ④.插入数据
- ⑤.查询数据
- 总结
前言
由于公司项目上进行面向对象的架构设计对于ORM部分使用的是Spring Data JPA框架。将ORM完全交给Spring Data JPA框架,而Hibernate是Spring Data JPA的实现方式之一,通过对HIbernate框架的学习能够更好的理解ORM框架,以及Spring Data JPA框架。
下面的博客是对于Hibernate框架中的基本映射中的多对一和一对多映射进行的实践,总结的并不全面,旨在多对一和一对多映射关系有一个宏观了解并能够进行基本运用。
一、多对一映射是什么?
在 Hibernate 中,多对一关联映射表示多个实体关联到另一个实体,即多个从实体关联到一个主实体。这种关系常用于表示层级关系或父子关系。
在多对一关联映射中,存在两个实体,即主实体和从实体。从实体包含对主实体的引用,而主实体通常是拥有外键的一方。
1.案例:现在有两个实体User实体和Group,其中多个User属于一个Group,表现出多对一的关系。
①.实体结构
package com.wangwei.hibernate;
import java.util.Date;
public class User {
private Integer id;
private String name;
private Group group;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Group getGroup() {
return group;
}
public void setGroup(Group group) {
this.group = group;
}
}
package com.wangwei.hibernate;
import java.util.Date;
public class Group {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
②.实体对象的xml配置
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.wangwei.hibernate.Group" table="t_group">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
</class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.wangwei.hibernate.User" table="t_user">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<many-to-one name="group" column="groupid" cascade="save-update"/>
</class>
</hibernate-mapping>
备注:
在多的一端采用如下标签映射:
<many-to-one name="group" column="groupid"/>
③.什么是级联?
级联是对象之间的连锁操作,它只影响添加、删除和修改
cascade表示级联操作:
常见的级联操作类型:级联保存:当一个实体进行保存操作是,级联保存将自动保存与该实体关联的所有实体。这样可以避免手动保存关联实体的麻烦。
级联更新、级联删除、级联刷新(当一个实体执行刷新操作时,级联刷新将自动刷新与该实体关联的所有实体,确保关联实体的数据与数据库中的数据保存一致)。
除了上面的一些操作之外,还可以进行组合如:级联保存更新、级联保存删除等等。
④.生成的表结构
⑤.往表中插入数据
核心代码:
public void saveTest3() {
Session session =null;
try {
session=HibernateUtils.getSession();
session.beginTransaction();
Group group=new Group();
group.setName("廊坊师范学院");
User user1=new User();
user1.setName("wangwei");
user1.setGroup(group);
User user2=new User();
user2.setName("lyy");
user2.setGroup(group);
session.save(user1);
session.save(user2);
//使用了级联特性
//hibernate会首先保存User的关联对象 Group
//Group和User都是Persistent状态的对象了
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
生成的sql语句
对应表中的数据
⑥.查询数据
核心代码:
public void loadTest1() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
User user = (User)session.load(User.class, 1);
System.out.println("user.name=" + user.getName());
System.out.println("user.group.name=" + user.getGroup().getName());
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
生成的sql语句和打印出的数据
二、一对多映射是什么?
在 Hibernate 中,一对多关联表示一个实体与多个关联实体之间的关系,其中一个实体拥有对多个关联实体的引用。这种关联关系通常使用集合来表示。
在一对多关联中,存在两个实体,即主实体和从实体。主实体拥有对从实体的集合引用,而从实体则包含一个对主实体的引用。
1.案例:现在有两个实体Classes实体和Student,其中一个班级包含多个学生,表现出一对多的关系。
①实体结构
package com.wangwei.hibernate;
import java.util.Set;
public class Classes {
private int id;
private String name;
private Set students;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set getStudents() {
return students;
}
public void setStudents(Set students) {
this.students = students;
}
}
package com.wangwei.hibernate;
public class Student {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
②.实体对应的xml配置
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.wangwei.hibernate.Student" table="t_student">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
</class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.wangwei.hibernate.Classes" table="t_classes">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<set name="students">
<!--
<key column="classesid" not-null="true"/>
-->
<key column="classesid"/>
<one-to-many class="com.wangwei.hibernate.Student"/>
</set>
</class>
</hibernate-mapping>
③.生成的表结构
④.插入数据
核心代码:
public void testSave2() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Student student1 = new Student();
student1.setName("张三");
session.save(student1);
Student student2 = new Student();
student2.setName("李四");
session.save(student2);
Classes classes = new Classes();
classes.setName("计算机");
Set students = new HashSet();
students.add(student1);
students.add(student2);
classes.setStudents(students);
//可以成功保存数据
//但是会发出多余的update语句来维持关系
session.save(classes);
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
发出的sql语句:
对应数据表中的数据:
⑤.查询数据
核心代码:
public void testLoad1() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Classes classes = (Classes)session.load(Classes.class, 1);
System.out.println("classes.name=" + classes.getName());
Set students = classes.getStudents();
for (Iterator iter=students.iterator(); iter.hasNext();) {
Student student = (Student)iter.next();
System.out.println("student.name=" +student.getName());
}
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
发出的sql语句和打印出的内容:
总结
-
一对多关联映射和多对一关联映射映射原理是一致的,都是在多的一端加入一个外键,指向一的一端。
-
与多对一不同的是,一对多维护的关系是:有一的一端维护关系,一指向多的关系,有了此关系,在加载一的时候可以将多加载上来。
-
但是一的一端维护关系存在缺陷:
因为多的一端Student不知道Classes的存在(也就是Student没有维护与Classes的关系)
所以在保存Student的时候关系字段classesid是为null的,如果将该关系字段设置为非空,则
将无法保存数据 -
另外因为Student不维护关系,而Classes维护关系,Classes就会发出多余的update语句,保证
Classes和Student有关系,这样加载Classes的时候才可以把该Classes对应的学生加载上来。发出多余的update语句本身效率上还是有些问题的。