系列文章目录
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语句本身效率上还是有些问题的。