05.Hibernate多对多关联
1.数据库表的多对多关系

CREATE TABLE tb_student(id bigint NOT NULL auto_increment COMMENT 'ID',no varchar(10) NOT NULL COMMENT '学号',name varchar(50) NOT NULL COMMENT '姓名',sex char(1) NOT NULL COMMENT '性别',birthday datetime COMMENT '出生日期',class_id bigint COMMENT '班级ID',PRIMARY KEY (id)) COMMENT = '学生信息表';CREATE TABLE tb_teacher(id bigint NOT NULL auto_increment COMMENT 'ID',no varchar(10) NOT NULL COMMENT '教师编号',name varchar(50) NOT NULL COMMENT '教师姓名',sex char(1) NOT NULL COMMENT '教师性别',job_title varchar(50) NOT NULL COMMENT '职称',PRIMARY KEY (id)) COMMENT = '教师信息表';CREATE TABLE tb_student_teacher(student_id bigint NOT NULL COMMENT '学生ID',teacher_id bigint NOT NULL COMMENT '教师ID',PRIMARY KEY (student_id,teacher_id)) COMMENT = '学生教师关系表';-- 可选的外键约束ALTER TABLE tb_student_teacher ADD CONSTRAINT fk_student_id FOREIGN KEY (student_id) REFERENCES tb_student (id);ALTER TABLE tb_student_teacher ADD CONSTRAINT fk_teacher_id FOREIGN KEY (teacher_id) REFERENCES tb_teacher (id);
package model;import java.sql.Date;import java.util.HashSet;import java.util.Set;public class Student{private Long id;private String no;private String name;private String sex;private Date birthday;private Long classId;private Set<Teacher> teachers=new HashSet<Teacher>();@Overridepublic String toString(){return "Student [id=" + id + ", no=" + no + ", name=" + name + ", sex=" + sex + ", birthday=" + birthday + ", classId=" + classId + ", teachers=" + teachers.size() + "]";}//省略setter、getter...}
package model;import java.util.HashSet;import java.util.Set;public class Teacher{private Long id;private String no;private String name;private String sex;private String job_title;private Set<Student> students=new HashSet<Student>();@Overridepublic String toString(){return "Teacher [id=" + id + ", no=" + no + ", name=" + name + ", sex=" + sex + ", job_title=" + job_title + ", students=" + students.size() + "]";}//省略setter、getter...}
2.单向多对多关系
<hibernate-mapping package="model"><class name="Student" table="tb_student"><id name="id"><generator class="native"></generator></id><property name="no" column="no"/><property name="name" column="name"/><property name="sex" column="sex"/><property name="birthday" column="birthday"/><property name="classId" column="class_id"/></class></hibernate-mapping>
<hibernate-mapping package="model"><class name="Teacher" table="tb_teacher"><id name="id" column="id"><generator class="native"></generator></id><property name="no" column="no" /><property name="name" column="name" /><property name="sex" column="sex" /><property name="job_title" column="job_title" /><set name="students" table="tb_student_teacher" cascade="save-update"><key column="teacher_id"/><many-to-many class="model.Student" column="student_id" /></set></class></hibernate-mapping>
- 由于实体类使用的是Set集合所以使用set元素配置关联关系,根据实体类的集合类型也可以对应的使用idbag、list、map元素。
- 由于tb_student表与tb_teacher表的多对多关系是通过tb_student_teacher表来保存的,所以set元素的table属性设置成table="tb_student_teacher"。
- set元素的key子元素设置column="teacher_id",表示tb_student_teacher表中参照tb_teacher表的外键设置为teacher_id。
- set元素的many-to-many子元素设置class="model.Student",表示Teacher类的students属性的类型,而其column="student_id",表示tb_student_teacher表中参照model.Student类型对应的表的外键设置为student_id。
- 所以set元素的cascade属性设置成save-update是很合理的,不允许把cascade设置成all、delete、all-delete-orphands,假如删除一个Teacher对象时还会级联删除与他关联的所有Student对象,由于Student对象可能还会与其他的Teacher对象关联,因此当Hibernate执行级联删除时会违反数据库的外键参照完整性!
public static void main(String[] args){Teacher teacher;Configuration cfg = new Configuration();cfg.configure();ServiceRegistry sr = new ServiceRegistryBuilder().applySettings(cfg.getProperties()).buildServiceRegistry();SessionFactory sf = cfg.buildSessionFactory(sr);System.out.println("连接数据库");Session session = sf.openSession();teacher =(Teacher) session.get(Teacher.class, new Long(1));System.out.println(teacher);System.out.println(teacher.getStudents());session.close();System.exit(0);}
连接数据库Hibernate:selectteacher0_.id as id1_7_0_,teacher0_.no as no2_7_0_,teacher0_.name as name3_7_0_,teacher0_.sex as sex4_7_0_,teacher0_.job_title as job_titl5_7_0_fromtb_teacher teacher0_whereteacher0_.id=?Hibernate:selectstudents0_.teacher_id as teacher_1_7_0_,students0_.student_id as student_2_6_0_,student1_.id as id1_5_1_,student1_.no as no2_5_1_,student1_.name as name3_5_1_,student1_.sex as sex4_5_1_,student1_.birthday as birthday5_5_1_,student1_.class_id as class_id6_5_1_fromtb_student_teacher students0_inner jointb_student student1_on students0_.student_id=student1_.idwherestudents0_.teacher_id=?Teacher [id=1, no=000001, name=教师1, sex=女, job_title=初级教师, students=1]Hibernate:selectteachers0_.student_id as student_2_5_0_,teachers0_.teacher_id as teacher_1_6_0_,teacher1_.id as id1_7_1_,teacher1_.no as no2_7_1_,teacher1_.name as name3_7_1_,teacher1_.sex as sex4_7_1_,teacher1_.job_title as job_titl5_7_1_fromtb_student_teacher teachers0_inner jointb_teacher teacher1_on teachers0_.teacher_id=teacher1_.idwhereteachers0_.student_id=?[Student [id=1, no=000001, name=学生1, sex=男, birthday=2015-01-27, classId=41, teachers=1]]关闭数据库
3.双向多对多关系
<hibernate-mapping package="model"><class name="Student" table="tb_student"><id name="id"><generator class="native"></generator></id><property name="no" column="no"/><property name="name" column="name"/><property name="sex" column="sex"/><property name="birthday" column="birthday"/><property name="classId" column="class_id"/><set name="teachers" table="tb_student_teacher" cascade="save-update" inverse="true"><key column="student_id"/><many-to-many class="model.Teacher" column="teacher_id"/></set></class></hibernate-mapping>
<hibernate-mapping package="model"><class name="Teacher" table="tb_teacher"><id name="id" column="id"><generator class="native"></generator></id><property name="no" column="no" /><property name="name" column="name" /><property name="sex" column="sex" /><property name="job_title" column="job_title" /><set name="students" table="tb_student_teacher" cascade="save-update" inverse="false"><key column="teacher_id"/><many-to-many class="model.Student" column="student_id" /></set></class></hibernate-mapping>
4.使用组件类集合映射多对多关联

package model;import java.sql.Date;import java.util.HashSet;import java.util.Set;public class Student{private Long id;private String no;private String name;private String sex;private Date birthday;private Long classId;private Set<TeacherAndStudent> teacherAndStudents = new HashSet<TeacherAndStudent>();@Overridepublic String toString(){return "Student [id=" + id + ", no=" + no + ", name=" + name + ", sex=" + sex + ", birthday=" + birthday + ", classId=" + classId + "]";}// 省略setter、getter...}
package model;import java.util.HashSet;import java.util.Set;public class Teacher{private Long id;private String no;private String name;private String sex;private String job_title;private Set<TeacherAndStudent> teacherAndStudents = new HashSet<TeacherAndStudent>();@Overridepublic String toString(){return "Teacher [id=" + id + ", no=" + no + ", name=" + name + ", sex=" + sex + ", job_title=" + job_title + "]";}// 省略setter、getter...}
package model;public class TeacherAndStudent{private Teacher teacher;private Student student;@Overridepublic String toString(){return "TeacherAndStudent [teacher=" + teacher + ", student=" + student + "]";}// 省略setter、getter...}
<hibernate-mapping package="model"><class name="Student" table="tb_student"><id name="id"><generator class="native"></generator></id><property name="no" column="no"/><property name="name" column="name"/><property name="sex" column="sex"/><property name="birthday" column="birthday"/><property name="classId" column="class_id"/><set name="teacherAndStudents" table="tb_student_teacher" cascade="save-update" inverse="true"><key column="student_id" /><composite-element class="TeacherAndStudent"><parent name="student" /><many-to-one name="teacher" class="Teacher" column="teacher_id"/></composite-element></set></class></hibernate-mapping>
<hibernate-mapping package="model"><class name="Teacher" table="tb_teacher"><id name="id" column="id"><generator class="native"></generator></id><property name="no" column="no" /><property name="name" column="name" /><property name="sex" column="sex" /><property name="job_title" column="job_title" /><set name="teacherAndStudents" table="tb_student_teacher" cascade="save-update" inverse="false"><key column="teacher_id"/><composite-element class="TeacherAndStudent"><parent name="teacher"/><many-to-one name="student" class="Student" column="student_id"/></composite-element></set></class></hibernate-mapping>
- 在Hibernate中使用composite-element元素映射组件类。
- composite-element元素下的parent元素用来设置当前组件所属的整体类。
- composite-element元素下还可以使用many-to-one元素和property元素等。
public static void main(String[] args){Teacher teacher;Configuration cfg = new Configuration();cfg.configure();ServiceRegistry sr = new ServiceRegistryBuilder().applySettings(cfg.getProperties()).buildServiceRegistry();SessionFactory sf = cfg.buildSessionFactory(sr);System.out.println("连接数据库");Session session = sf.openSession();teacher =(Teacher) session.get(Teacher.class, new Long(1));System.out.println(teacher);System.out.println(teacher.getTeacherAndStudents());session.close();System.exit(0);}
连接数据库Hibernate:selectteacher0_.id as id1_7_0_,teacher0_.no as no2_7_0_,teacher0_.name as name3_7_0_,teacher0_.sex as sex4_7_0_,teacher0_.job_title as job_titl5_7_0_fromtb_teacher teacher0_whereteacher0_.id=?Teacher [id=1, no=000001, name=教师1, sex=女, job_title=初级教师]Hibernate:selectteacherand0_.teacher_id as teacher_1_7_0_,teacherand0_.student_id as student_2_6_0_,student1_.id as id1_5_1_,student1_.no as no2_5_1_,student1_.name as name3_5_1_,student1_.sex as sex4_5_1_,student1_.birthday as birthday5_5_1_,student1_.class_id as class_id6_5_1_fromtb_student_teacher teacherand0_left outer jointb_student student1_on teacherand0_.student_id=student1_.idwhereteacherand0_.teacher_id=?[TeacherAndStudent [teacher=Teacher [id=1, no=000001, name=教师1, sex=女, job_title=初级教师], student=Student [id=1, no=000001, name=学生1, sex=男, birthday=2015-01-27, classId=41]]]Hibernate:deletefromtb_student_teacherwhereteacher_id=?Hibernate:insertintotb_student_teacher(teacher_id, student_id)values(?, ?)关闭数据库
5.把多对多分解成两个一对多
CREATE TABLE tb_teacher_student(id bigint NOT NULL auto_increment COMMENT 'ID',student_id bigint COMMENT '学生ID',teacher_id bigint COMMENT '教师ID',PRIMARY KEY (id)) COMMENT = '教师学生关系表';
package model;public class StudentTeacher{private Long id;private Teacher teacher;private Student student;@Overridepublic String toString(){return "StudentTeacher [id=" + id + ", teacher=" + teacher + ", student=" + student + "]";}// 省略setter、getter...}
package model;import java.sql.Date;import java.util.HashSet;import java.util.Set;public class Student{private Long id;private String no;private String name;private String sex;private Date birthday;private Long classId;private Set<StudentTeacher> studentTeachers = new HashSet<StudentTeacher>();@Overridepublic String toString(){return "Student [id=" + id + ", no=" + no + ", name=" + name + ", sex=" + sex + ", birthday=" + birthday + ", classId=" + classId + "]";}// 省略setter、getter...}
package model;import java.util.HashSet;import java.util.Set;public class Teacher{private Long id;private String no;private String name;private String sex;private String job_title;private Set<StudentTeacher> studentTeachers = new HashSet<StudentTeacher>();@Overridepublic String toString(){return "Teacher [id=" + id + ", no=" + no + ", name=" + name + ", sex=" + sex + ", job_title=" + job_title + "]";}// 省略setter、getter...}
<hibernate-mapping package="model"><class name="StudentTeacher" table="tb_teacher_student"><id name="id" column="id"><generator class="native"></generator></id><many-to-one name="teacher" column="teacher_id" class="Teacher"/><many-to-one name="student" column="student_id" class="Student"/></class></hibernate-mapping>
<hibernate-mapping package="model"><class name="Teacher" table="tb_teacher"><id name="id" column="id"><generator class="native"></generator></id><property name="no" column="no" /><property name="name" column="name" /><property name="sex" column="sex" /><property name="job_title" column="job_title" /><set name="studentTeachers" inverse="true" cascade="save-update"><key column="teacher_id" /><one-to-many class="StudentTeacher"/></set></class></hibernate-mapping>
<hibernate-mapping package="model"><class name="Student" table="tb_student"><id name="id"><generator class="native"></generator></id><property name="no" column="no"/><property name="name" column="name"/><property name="sex" column="sex"/><property name="birthday" column="birthday"/><property name="classId" column="class_id"/><set name="studentTeachers" inverse="true" cascade="save-update"><key column="student_id" /><one-to-many class="StudentTeacher"/></set></class></hibernate-mapping>
......省略打开session的代码try{teacher =(Teacher) session.get(Teacher.class, new Long(1));student = (Student) session.get(Student.class, new Long(1));StudentTeacher st=new StudentTeacher();st.setStudent(student);st.setTeacher(teacher);student.getStudentTeachers().add(st);session.update(student);transaction.commit();}......省略关闭session的代码
连接数据库Hibernate:........ 省略若干获取关联对象的查询语句Hibernate: insert into tb_teacher_student (teacher_id, student_id) values (?, ?)关闭数据库
6.相关配置详解
<set name="EntityClassName"access="field|property|ClassName"collection-type="collection-type"schema="schema"catalog="catalog"check="arbitrary sql check condition"table="TableName"subselect="SQL expression"where="arbitrary sql where condition"sort="unsorted"optimistic-lock="false|true"inverse="false|true"fetch="join|select"batch-size="5"cascade="all|none|save-update|delete"lazy="false|true"mutable="false|true"outer-join="false|true"order-by="arbitrary sql order by condition"embed-xml="false|true"persister="PersisterClass"node="element-name"/>
- name:实体类属性名。
- access:默认的实体类属性访问模式,取值为property表示访问getter、setter方法间接访问实体类字段,取值为field表示直接访问实体类字段(类成员变量)。
- collection-type:
- schema:数据库schema。
- catalog:数据库catalog。
- check:这是一个SQL表达式,用于为自动生成的schema添加多行约束检查。
- table:此集合里的实体类对应的数据库表名。
- subselect:一个SQL子查询,它将一个不可变并且只读的实体映射到一个数据库的子查询。
- where:一个SQL查询的where条件,获取这个关联类的对象时会一直增加这个条件。
- sort:用来定义集合的排序规则,sort="natural"表示使用对象的comparaTo()方法排序。
- optimistic-lock:指定这个属性在做更新时是否需要获得乐观锁定,默认为true。
- inverse:当设置inverse="true"时,Hibernate将根此集合里的实体类类型的关联属性维护关联关系,默认值false。
- fetch:参数指定了关联对象抓取的方式是select查询还是join查询,默认为select。fetch="join"等同于outer-join="true",fetch="select"等同于outer-join="false"。
- batch-size:用于设置批次操作的SQL语句的数量,默认为1。
- cascade:指明哪些操作会从父对象级联到关联的对象。
- lazy:是否采用延迟加载策略。
- mutable:此集合里的实体类是否会发生改变,如果类实例对应的数据库表记录不会发生更新,可将其设为false,适用于单纯的Insert操作不使用update操作。
- outer-join:设置Hibernate是否使用外连接获取关联的数据,设置成true可以减少SQL语句的条数。
- order-by:一个SQL查询的order by条件,获取这个关联类的对象时会一直增加这个条件。
- embed-xml:如果embed-xml="true",则对应于被关联实体或值类型的集合的XML树将直接嵌入拥有这些关联的实体的XML树中,默认值为true。
- persister:指定持久化实现类,通过指定持久化类,我们可以实现自定义的持久化方法。持久化类为ClassPersister接口的实现。
- node:配置说明。
<composite-element class="ClassName" node="element-name"><parent name="PropertyName" /><property name="PropertyName"></property><many-to-one /></composite-element>
- class:用于设置组件的类型。
- node:配置说明。
- parent name:组件所属的实体类类型,值一般是组件类本身的实体类属性。
- property:组件类属性名。
- many-to-one:用于配置组件类的关联关系,不仅能使用many-to-one元素,还可使用其他的关联映射配置。
-------------------------------------------------------------------------------------------------------------------------------
05.Hibernate多对多关联的更多相关文章
- hibernate多对多关联映射
关联是类(类的实例)之间的关系,表示有意义和值得关注的连接. 本系列将介绍Hibernate中主要的几种关联映射 Hibernate一对一主键单向关联Hibernate一对一主键双向关联Hiberna ...
- atitit.atitit.hb many2one relate hibernate 多对一关联配置..
atitit.atitit.hb many2one relate hibernate 多对一关联配置.. 1. 多对一单向 @ManyToOne 1 1. 其中@JoinColumn 注解 2 2. ...
- Hibernate多对多关联
多对多关联: 示例:Teacher和Student,一个Teacher可以教很多student,一个Student也可以被很多teacher教 多对多单向关联 Teacher知道自己教了哪些学生, ...
- Hibernate多对多关联映射的HQL中的in条件查询问题
群里有朋友求解一个问题,高分求一条HQL多对多查询语句 . 问题描述见 http://topic.csdn.net/u/20090621/16/4eac6fe0-bf3e-422e-a697-f758 ...
- Hibernate 多对一关联查询
版权声明:本文为博主原创文章,如需转载请标注转载地址. 博客地址:http://www.cnblogs.com/caoyc/p/5598269.html 一.单向多对一和双向多对一的区别 如果只 ...
- Hibernate 多对多关联映射, 中间表加查询条件
package com.coracle.yk.xpo.po.base; import java.util.Date; import java.util.HashSet; import java.uti ...
- Hibernate 多对多关联Demo
以学生[Student ]与课程[Course ]之间的关系为例: //Course .java public class Course implements Serializable { priva ...
- hibernate 多对一关联
(转自尚学堂教学内容) 注解多对一: package com.bjsxt.hibernate; import javax.persistence.Entity; import javax.pers ...
- Hibernate 多对多关联查询条件使用
from Brand as b inner join fetch b.styles as s where s.styleId=?
随机推荐
- 显示或隐藏一个Grid
The Rowset class contains two methods that can be used to show and hide all rows: ShowAllRows() Hide ...
- vue.js插件使用(01) vue-resource
本文的主要内容如下: 介绍vue-resource的特点 介绍vue-resource的基本使用方法 基于this.$http的增删查改示例 基于this.$resource的增删查改示例 基于int ...
- mariadb的explain分析及InnoDB存储引擎
id: 当前查询语句中,每个SELECT语句的编号, id: 1 表示简单类型的查询 复杂类型的查询有三种:简单子查询,用于FROM中的子查询,联合查询:UNION 注意:UNION查询的分 ...
- ThinkPHP之中的事务回滚
小李子 获取thinkphp之中执行的SQL: 1.用调试模式的追踪trace功能: 2.代码: $user_type=D('user_type'); $datass=array('school_id ...
- jQuery在HTML文档加载完毕后自动执行某个事件;
原来onchange=“fucntionname(parms)”: <select name="country" id="selCountries_{$sn}&qu ...
- python 解析XML python模块xml.dom解析xml实例代码
分享下python中使用模块xml.dom解析xml文件的实例代码,学习下python解析xml文件的方法. 原文转自:http://www.jbxue.com/article/16587.html ...
- 随机获取Mysql数据表的一条或多条记录
随机获得Mysql数据表的一条或多条记录有很多方法,下面我就以users(userId,userName,password......)表(有一百多万条记录)为例,对比讲解下几个方法效率问题: sel ...
- 取消界面的title
在setContentView(R.layout.activity_main)方法上面添加代码(继承Activity的写法): requestWindowFeature(Window.FEATURE_ ...
- Oracle 11g 之自动收集统计信息
在Oracle的11g版本中提供了统计数据自动收集的功能.在部署安装11g Oracle软件过程中,其中有一个步骤便是提示是否启动这个功能(默认是启用这个功能). 1.查看自动收集统计信息的任务及状态 ...
- SQLServer异常捕获
在SQLserver数据库中,如果有很多存储过程的时候,我们会使用动态SQL进行存储过程调用存储过程,这时候,很可能在某个环节就出错了,但是出错了我们很难去跟踪到出错的存储过程,此时我们就可以使用异常 ...