Hibernate框架进阶(中篇)之多表关系
导读
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框架进阶(中篇)之多表关系的更多相关文章
- Hibernate框架进阶(上篇)
导读 前面一片文章介绍了Hibernate框架的入门,主要是讲解Hibernate的环境搭建和简单测试,有兴趣的童鞋出门左转.本文在入门的基础上进行Hibernate的进阶讲解,分为上中下三篇,本篇为 ...
- Hibernate框架进阶(下篇)之查询
导读 Hibernate进阶篇分为上中下三篇,本文为最后一篇,主要内容是Hibernate框架的查询,主要包括hql语句查询,criteria查询以及查询策略的选择. 知识框架 Hibernate查询 ...
- JPA、Hibernate框架、通用mapper之间的关系及通用mapper的具体实现
JPA是描述对象-关系表的映射关系,将运行期实体对象持久化到数据库中,提出以面向对象方式操作数据库的思想. Hibernate框架核心思想是ORM-实现自动的关系映射.缺点:由于关联操作提出Hql语法 ...
- Hibernate框架双向多对多关联映射关系
建立双向多对多关联关系 Project.java (项目表) private Integer proid; private Strin ...
- Hibernate框架单向多对一关联映射关系
建立多对一的单向关联关系 Emp.java private Integer empNo //员工编号 private String empName / ...
- Hibernate框架单向多对多关联映射关系
建立单向多对多关联关系 Project.java (项目表) private Integer proid; private Strin ...
- Php Laravel框架 多表关系处理 之 Eloquent一对多关系处理
Php Laravel框架 多表关系处理 之 Eloquent一对多关系处理 本博文主要介绍 Laravel 框架中 Eloquent 对一对多关系的处理以及在 Laravel Administra ...
- Hibernate框架学习之注解配置关系映射
上篇文章我们通过注解对映射了单个实体类,但是具体项目中往往实体类之间又是相互关联的,本篇文章就是从实体类之间存在的不同关联角度,具体学习下如何映射他们之间的关联,主要涉及内容如下: 单向的一 ...
- Hibernate框架笔记03表操作多对多配置
目录 1. 数据库表与表之间的关系 1.1 一对多关系 1.2 多对多关系 1.3 一对一关系[了解] 2. Hibernate的一对多关联映射 2.1 创建一个项目,引入相关jar包 2.2. 创建 ...
随机推荐
- 业余草双因素认证(2FA)教程
所谓认证(authentication)就是确认用户的身份,是网站登录必不可少的步骤.密码是最常见的认证方法,但是不安全,容易泄露和冒充.越来越多的地方,要求启用双因素认证(Two-factor au ...
- 微信公众号开发(十二)OAuth2.0网页授权
OAuth允许用户提供一个令牌,而不是用户名和密码来访问它们存放在特定服务器上的数据,每一个令牌授权一个特定的网站在特定时段内访问特定的资源. 授权过程如下: 1.引导用户进入授权页面同意授权,获取c ...
- 《Spark Python API 官方文档中文版》 之 pyspark.sql (二)
摘要:在Spark开发中,由于需要用Python实现,发现API与Scala的略有不同,而Python API的中文资料相对很少.每次去查英文版API的说明相对比较慢,还是中文版比较容易get到所需, ...
- 「设计模式」JavaScript - 设计模式之单例模式与场景实践
单例介绍 上次总结了设计模式中的module模式,可能没有真真正正的使用在场景中,发现效果并不好,想要使用起来却不那么得心应手, 所以这次我打算换一种方式~~从简单的场景中来看单例模式, 因为Java ...
- JavaNIO非阻塞模式
package com.java.NIO; import java.io.IOException; import java.net.InetSocketAddress; import java.nio ...
- AngularJS学习篇(十七)
AngularJS 输入验证 <!DOCTYPE html> <html> <script src="http://apps.bdimg.com/libs/an ...
- Grunt参考
Grunt参考: http://www.cnblogs.com/yexiaochai/p/3603389.html http://blog.csdn.net/wangfupeng1988/articl ...
- 开发环境MAPLAB下使用仿真器ICD2程序下载流程
程序下载流程 一. 连接示意图 二. 下载步骤 1.目标板电源断开 2.将仿真器下载端口与电路板JTAG端口有效连接 3.启动MPLAB软件 4.点击MAPLAB软件上方Programme ...
- Celery 源码解析四: 定时任务的实现
在系列中的第二篇我们已经看过了 Celery 中的执行引擎是如何执行任务的,并且在第三篇中也介绍了任务的对象,但是,目前我们看到的都是被动的任务执行,也就是说目前执行的任务都是第三方调用发送过来的.可 ...
- Velocity(6)——velocity遍历josn格式的字符串
使用velocity脚本语言遍历josn格式的字符串 1.由于数据库会存储一些json格式的字符,为方便以后使用筛选 如果这些数据我们查出来直接遍历使用velocity是根本行不通的,例如这样的话:j ...