系列文章目录
基本映射——多对一和一对多映射
前言
由于公司项目上进行面向对象的架构设计对于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语句本身效率上还是有些问题的。