导读

Hibernate进阶主要分为上中下三篇,本文是中篇,主要讲解Hibernate框架中多表关系的实现。我们知道多表关系有一对一、一对多(多对一)和多对多三种关系。而1对1关系一般合并为一个表处理,所以本文主要讲解1对多和多对多关系的实现。

一、一对多关系

一对多的关系很多,比如人和籍贯就是一对多的关系,下面就用人和籍贯这个实例来展开说明。

1、数据库的实现

对于一对多关系的建立,我们通常是使用外键(foreign key)来表示。外键列添加在一对多的“多”这一方。这里用person表和province表分别表示人和籍贯,所以外键就加入person表中,值就是province表的主键值。

2、实体类的实现

对应数据库表,实体类分别用Person类和Province类表示。而在实体类中就没有外键这种概念了。

对于Person类是“多对一”,即很多人属于同一个省份。所以怎么在Person类中表示所属的这一个省份呢?使用类Province即可。

反过来对于Province类是“一对多”,即一个省份有很多人。那么怎么表示很多人呢?即很多Person类,所以我们很快想到使用集合来保存Person类,这里我们使用Set集合。(Set集合值不会重复更符合实际的需求)。

所以,最终的类实现如下:

 package domain;

 public class Person {
private Long per_id;//省份证
private String name;//姓名
private Integer age;//年龄 //关系
private Province province;//所属省份 public Long getPer_id() {
return per_id;
} public void setPer_id(Long per_id) {
this.per_id = per_id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Integer getAge() {
return age;
} public void setAge(Integer age) {
this.age = age;
} public Province getProvince() {
return province;
} public void setProvince(Province province) {
this.province = province;
} @Override
public String toString() {
return "Person [per_id=" + per_id + ", name=" + name + ", age=" + age + ", province=" + province + "]";
}
}

Person

 package domain;

 import java.util.HashSet;
import java.util.Set; public class Province {
private Long pro_id;//省代码
private String name;//省名 //关系
private Set<Person> personSet = new HashSet<Person>();//省份的人口集合 public Long getPro_id() {
return pro_id;
} public void setPro_id(Long pro_id) {
this.pro_id = pro_id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Set<Person> getPersonSet() {
return personSet;
} public void setPersonSet(Set<Person> personSet) {
this.personSet = personSet;
}
@Override
public String toString() {
return "Province [pro_id=" + pro_id + ", name=" + name + ", personSet=" + personSet + "]";
}
}

Province

3、数据库表和实体类的映射关系

配置文件主要是orm元数据(映射关系)和主配置文件的配置。

3.1、orm元数据的配置

orm元数据的配置和之前的配置几乎一致,主要是如何在配置文件中表示外键。具体看下面的配置方法:

 <?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="domain" > <class name="Person" table="person" >
<id name="per_id" >
<generator class="identity"></generator>
</id> <property name="name" column="name" ></property>
<property name="age" column="age" ></property> <!-- 多对一关系的配置: -->
<many-to-one name="province" column="pro_id" class="Province" ></many-to-one> </class>
</hibernate-mapping>

Person.hbm.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="domain" > <class name="Province" table="province" >
<id name="pro_id" >
<generator class="identity"></generator>
</id> <property name="name" column="name" ></property> <!-- 一对多关系的配置: -->
<set name="personSet">
<key column="pro_id"></key>
<one-to-many class="Person"/>
</set> </class>
</hibernate-mapping>

Province.hbm.xml

总结:

多对一:

一对多:

3.2、主配置文件的配置

 <?xml version="1.0" encoding="UTF-8"?>
<!-- 导入约束 -->
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<!-- 主配置文件 -->
<hibernate-configuration>
<session-factory>
<!--
#hibernate.dialect org.hibernate.dialect.MySQLDialect
#hibernate.dialect org.hibernate.dialect.MySQLInnoDBDialect
#hibernate.dialect org.hibernate.dialect.MySQLMyISAMDialect
#hibernate.connection.driver_class com.mysql.jdbc.Driver
#hibernate.connection.url jdbc:mysql:///test
#hibernate.connection.username gavin
#hibernate.connection.password
-->
<!-- 数据库驱动 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- 数据库url -->
<property name="hibernate.connection.url">jdbc:mysql:///hibernate</property>
<!-- 数据库连接用户名 -->
<property name="hibernate.connection.username">root</property>
<!-- 数据库连接密码 -->
<property name="hibernate.connection.password">password</property>
<!-- 数据库方言 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <property name="hibernate.current_session_context_class">thread</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property> <!-- 引入orm元数据-->
<mapping resource="domain/Person.hbm.xml" />
<mapping resource="domain/Province.hbm.xml" /> </session-factory>
</hibernate-configuration>

hibernate.cfg.xml

4、Hibernate代码测试

 package Test;

 import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test; import domain.Person;
import domain.Province;
import utils.HibernateUtils; public class Demo { @Test
public void test(){
//1、创建对话session
Session session = HibernateUtils.openSession();
//2、开启事务
Transaction tx = session.beginTransaction(); //3、操作事务:假设张三和李四籍贯北京,现在讲数据持久化到数据库中
//---------------------------------
//创建实体对象
Province pro = new Province();
pro.setName("北京");
Person p1 = new Person();
Person p2 = new Person();
p1.setName("张三");
p2.setName("李四"); //建立对象之间的关系
//一对多:
pro.getPersonSet().add(p1);
pro.getPersonSet().add(p2);
//多对一
p1.setProvince(pro);
p2.setProvince(pro); //将信息持久化到数据库
session.save(pro);
session.save(p1);
session.save(p2); //---------------------------------- //4、提交事务
tx.commit();
//5、关闭资源
session.close();
}
}

测试结果:

5、扩展:cascade属性和reverse属性

1)cascade属性

cascade属性是配置级联操作的一个配置属性,cascade的属性值有:save-update(级联保存)、delete(级联删除)、all(级联保存和删除)。

级联的意思是当你配置了这个属性,那么你操作这个对象时对应的关系对象也会进行相应操作。比如我在上面的Province映射关系中配置了:

那么当我执行session.save(pro)时就不必再执行session.save(p1)和session.save(p2)。

结论:该属性是用来简化书写的,如果要使用,建议不要使用delete和all,因为级联删除存在很大风险,可能会无意中删除很多数据。

2)reverse属性

另一个属性reverse在一对多关系中可以用来优化性能。reverse有两个值:true和false。当选择true是表示放弃维护外键,默认是false。(这个属性在多对多关系中必须使用,因为不能使用两个表来同时维护外键)。

二、多对多关系

1、数据库的实现

多对多的关系是通过转换为两个一对多来实现的。例如学生选课这个关系,一个学生可以选多门课,每个课程又可以对应很多学生,即多对多关系。这样我们就可以在student表和course表之间增加一个关系表choose表(选课表),用来存储学生id和课程id,以此来建立对应关系。这样多对多的关系就变成了两个一对多的关系。

2、实体类的实现

实体类的创建和一对多是一样的道理。

 package domain;

 import java.util.HashSet;
import java.util.Set; public class Student {
private Long sid;//学号
private String sname;//姓名 private Set<Course> courseSet = new HashSet<Course>();//选课信息 public Long getSid() {
return sid;
} public void setSid(Long sid) {
this.sid = sid;
} public String getSname() {
return sname;
} public void setSname(String sname) {
this.sname = sname;
} public Set<Course> getCourseSet() {
return courseSet;
} public void setCourseSet(Set<Course> courseSet) {
this.courseSet = courseSet;
} }

Student

 package domain;

 import java.util.HashSet;
import java.util.Set; public class Course {
private Long cid;//课程代码
private String cname;//课程名 private Set<Student> studentSet = new HashSet<Student>();//学生信息 public Long getCid() {
return cid;
} public void setCid(Long cid) {
this.cid = cid;
} public String getCname() {
return cname;
} public void setCname(String cname) {
this.cname = cname;
} public Set<Student> getStudentSet() {
return studentSet;
} public void setStudentSet(Set<Student> studentSet) {
this.studentSet = studentSet;
} }

Course

3、数据库表和实体类的映射关系

这里的配置和之前的配置也是几乎不变,关键在于多对多关系的配置。

 <?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="domain" > <class name="Student" table="student" >
<id name="sid" >
<generator class="identity"></generator>
</id> <property name="sname" column="sname" ></property> <!-- 多对多关系的配置: -->
<set name="courseSet" table="choose" >
<key column="sid"></key>
<many-to-many class="Course" column="cid"></many-to-many>
</set> </class>
</hibernate-mapping>

Student.hbm.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="domain" > <class name="Course" table="course" >
<id name="cid" >
<generator class="identity"></generator>
</id> <property name="cname" column="cname" ></property> <!-- 多对多关系的配置: -->
<set name="studentSet" table="choose" inverse="true">
<key column="cid"></key>
<many-to-many class="Student" column="sid"></many-to-many>
</set> </class>
</hibernate-mapping>

Course.hbm.xml

变化:

Student.hbm.xml中

Course.hbm.xml中

主配置文件中:

5、测试

package Test;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test; import domain.Course;
import domain.Student;
import utils.HibernateUtils; public class Demo2 {
@Test
public void test(){
//1、创建对话session
Session session = HibernateUtils.openSession();
//2、开启事务
Transaction tx = session.beginTransaction(); //3、操作事务:假设有语数外三门课,张三选了语文和数学,李四选了语文和英语,Tom选了数学。将上述信息持久化到数据库
//---------------------------------
//创建实体对象
Course c1 = new Course();
c1.setCname("语文");
Course c2 = new Course();
c2.setCname("数学");
Course c3 = new Course();
c3.setCname("英语"); Student s1 = new Student();
s1.setSname("张三");
Student s2 = new Student();
s2.setSname("李四");
Student s3 = new Student();
s3.setSname("Tom"); //建立对象之间的关系
//课程对应学生
c1.getStudentSet().add(s1);
c1.getStudentSet().add(s2);
c2.getStudentSet().add(s2);
c2.getStudentSet().add(s3);
c3.getStudentSet().add(s2); //学生对应课程
s1.getCourseSet().add(c1);
s1.getCourseSet().add(c2);
s2.getCourseSet().add(c2);
s2.getCourseSet().add(c3);
s3.getCourseSet().add(c2); //将信息持久化到数据库
session.save(c1);
session.save(c2);
session.save(c3);
session.save(s1);
session.save(s2);
session.save(s3);
//---------------------------------- //4、提交事务
tx.commit();
//5、关闭资源
session.close();
}
}

测试结果:

Hibernate框架进阶(中篇)之多表关系的更多相关文章

  1. Hibernate框架进阶(上篇)

    导读 前面一片文章介绍了Hibernate框架的入门,主要是讲解Hibernate的环境搭建和简单测试,有兴趣的童鞋出门左转.本文在入门的基础上进行Hibernate的进阶讲解,分为上中下三篇,本篇为 ...

  2. Hibernate框架进阶(下篇)之查询

    导读 Hibernate进阶篇分为上中下三篇,本文为最后一篇,主要内容是Hibernate框架的查询,主要包括hql语句查询,criteria查询以及查询策略的选择. 知识框架 Hibernate查询 ...

  3. JPA、Hibernate框架、通用mapper之间的关系及通用mapper的具体实现

    JPA是描述对象-关系表的映射关系,将运行期实体对象持久化到数据库中,提出以面向对象方式操作数据库的思想. Hibernate框架核心思想是ORM-实现自动的关系映射.缺点:由于关联操作提出Hql语法 ...

  4. Hibernate框架双向多对多关联映射关系

    建立双向多对多关联关系    Project.java (项目表)                private Integer proid;                private Strin ...

  5. Hibernate框架单向多对一关联映射关系

    建立多对一的单向关联关系    Emp.java            private Integer empNo //员工编号            private String empName / ...

  6. Hibernate框架单向多对多关联映射关系

    建立单向多对多关联关系    Project.java (项目表)                private Integer proid;                private Strin ...

  7. Php Laravel框架 多表关系处理 之 Eloquent一对多关系处理

    Php Laravel框架 多表关系处理 之 Eloquent一对多关系处理 本博文主要介绍 Laravel 框架中 Eloquent  对一对多关系的处理以及在 Laravel Administra ...

  8. Hibernate框架学习之注解配置关系映射

         上篇文章我们通过注解对映射了单个实体类,但是具体项目中往往实体类之间又是相互关联的,本篇文章就是从实体类之间存在的不同关联角度,具体学习下如何映射他们之间的关联,主要涉及内容如下: 单向的一 ...

  9. Hibernate框架笔记03表操作多对多配置

    目录 1. 数据库表与表之间的关系 1.1 一对多关系 1.2 多对多关系 1.3 一对一关系[了解] 2. Hibernate的一对多关联映射 2.1 创建一个项目,引入相关jar包 2.2. 创建 ...

随机推荐

  1. 最新版multer1.3.0上传文件

    完整项目资源下载路径:http://download.csdn.net/detail/qq_28506819/9851744 使用方法: cd到跟目录,然后npm install. 运行项目,npm ...

  2. CSharpGL(45)自制控件的思路

    CSharpGL(45)自制控件的思路 +BIT祝威+悄悄在此留下版了个权的信息说: 本文介绍CSharpGL实现自制控件的方法. 所谓自制控件,就是用纯OpenGL模仿WinForm里的Button ...

  3. [转]Java - 集合框架完全解析

    数据结构是以某种形式将数据组织在一起的集合,它不仅存储数据,还支持访问和处理数据的操作.Java提供了几个能有效地组织和操作数据的数据结构,这些数据结构通常称为Java集合框架.在平常的学习开发中,灵 ...

  4. Special Fish

    Special Fish Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total ...

  5. CSS3 动画 animation和@keyframes

    CSS3 @keyframes 规则 如需在 CSS3 中创建动画,您需要学习 @keyframes 规则. @keyframes 规则用于创建动画.在 @keyframes 中规定某项 CSS 样式 ...

  6. JavaScript系列----作用域链和闭包

    1.作用域链 1.1.什么是作用域 谈起作用域链,我们就不得不从作用域开始谈起.因为所谓的作用域链就是由多个作用域组成的.那么, 什么是作用域呢? 1.1.1作用域是一个函数在执行时期的执行环境. 每 ...

  7. 实现基于LVS负载均衡集群的电商网站架构

    背景 上一期我们搭建了小米网站,随着业务的发展,网站的访问量越来越大,网站访问量已经从原来的1000QPS,变为3000QPS,网站已经不堪重负,响应缓慢,面对此场景,单纯靠单台LNMP的架构已经无法 ...

  8. Java 8的新特性—终极版

    作者:杜琪[译] 原文链接:http://www.jianshu.com/p/5b800057f2d8 1. 简介 毫无疑问,Java 8是Java自Java 5(发布于2004年)之后的最重要的版本 ...

  9. border-sizing属性

    box-sizing属性可以为三个值之一:content-box(default),border-box,padding-box. content-box,border和padding不计算入widt ...

  10. 【手记】让Fiddler抓取入站请求,或者叫用Fiddler做反向代理

    注意:本文不涉及HTTPS的场景 最近在弄公众号开发,除了主动去调公众号接口,还存在公众号后台要反过来调你的情形,攻受转换一线间.对于回调的情况,想要知道对方是怎样来请求的很有必要.此前经常用Fidd ...