Hibernate表关系映射之多对多映射
一、多对多的实现原理
在数据库中实现多对多的关系,必须使用连接表。也就是用一个独立的表来存入两个表的主键字段,通过遍历这张表来获取两表的关联关系。
而在我们的对象中,多对多是通过两者对象类中互相建立对方类的对象集合,类似上一篇讲到的一对多的集合类!
在Hibernate中是通过<many to many>来进行设置。同样多对多也存在双向和单向之分,表现到Hibernate中就是配置文件和POJO代码的不同。这里以单向映射为例,双向映射与之类似。
二、实例演示
1、建立数据模型
我们以学生与老师关系为例。一个学生可以有多个老师,而一个老师也一样可以有多名学生!这里我们让老师Teacher持有学生Student的集合引用。
Teacher.java
package com.chen.many2many; import java.util.HashSet;
import java.util.Set; public class Teacher {
private Integer teacherID;
private String teacherName;
//持有一个student的Set集合
private Set<Student> studentSet=new HashSet<>(); public Integer getTeacherID() {
return teacherID;
}
public void setTeacherID(Integer teacherID) {
this.teacherID = teacherID;
}
public String getTeacherName() {
return teacherName;
}
public void setTeacherName(String teacherName) {
this.teacherName = teacherName;
}
public Set<Student> getStudentSet() {
return studentSet;
}
public void setStudentSet(Set<Student> studentSet) {
this.studentSet = studentSet;
} }
Student.java
package com.chen.many2many; import java.util.HashSet;
import java.util.Set; public class Student {
private Integer studentID;
private String studentName;
//持有一个teacher的Set集合
//private Set<Teacher> teacherSet=new HashSet<>();
public Integer getStudentID() {
return studentID;
}
public void setStudentID(Integer studentID) {
this.studentID = studentID;
}
public String getStudentName() {
return studentName;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
/* public Set<Teacher> getTeacherSet() {
return teacherSet;
}
public void setTeacherSet(Set<Teacher> teacherSet) {
this.teacherSet = teacherSet;
}
*/ }
2、Hibernate配置文件
Student.hbm.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">
<!-- Generated 2017-3-10 14:43:39 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
<class name="com.chen.many2many.Student" table="STUDENTS">
<id name="studentID" type="java.lang.Integer">
<column name="STUDENT_ID" />
<generator class="native" />
</id>
<property name="studentName" type="java.lang.String">
<column name="STUDENT_NAME" />
</property>
<!-- 指定双向映射时需要加入如下设置
<set name="teacherSet" table="TEACHERS_STUDENTS" inverse="true">
<key>
<column name="S_ID" />
</key>
<many-to-many class="com.chen.many2many.Teacher" column="T_ID"/>
</set> -->
</class>
</hibernate-mapping>
Teacher.hbm.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">
<!-- Generated 2017-3-10 14:43:39 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
<class name="com.chen.many2many.Teacher" table="TEACHERS">
<id name="teacherID" type="java.lang.Integer">
<column name="TEACHER_ID" />
<generator class="native" />
</id>
<property name="teacherName" type="java.lang.String">
<column name="TEACHER_NAME" />
</property>
<!-- name是该类(Teacher)中持有的另一端的集合属性名 ,table指定了中间表的名字-->
<set name="studentSet" table="TEACHERS_STUDENTS">
<key>
<!-- 当前类(Teacher)映射到中间表上时,使用的外键名称 -->
<column name="T_ID" />
</key>
<!-- many-to-many完成多对多映射,class指定另一端(Student)的类名。
column指定另一端(Student)在中间表中对应的外键名 -->
<many-to-many class="com.chen.many2many.Student" column="S_ID" />
</set>
</class>
</hibernate-mapping>
hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory> <!-- Hibernate 连接数据库的基本信息 -->
<property name="connection.username">root</property>
<property name="connection.password">root</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://192.168.1.148:3306/hibernate5</property> <!-- Hibernate 的基本配置 -->
<!-- Hibernate 使用的数据库方言,为了使mysql自动生成数据表
对于mysql5.x使用如下设置 -->
<property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property> <!-- 运行时是否打印 SQL -->
<property name="show_sql">true</property> <!-- 运行时是否格式化 SQL -->
<property name="format_sql">true</property> <!-- 生成数据表的策略 -->
<property name="hbm2ddl.auto">update</property> <!-- 设置 Hibernate 的事务隔离级别 -->
<property name="connection.isolation">2</property> <!-- 删除对象后, 使其 OID 置为 null -->
<property name="use_identifier_rollback">true</property> <!-- 配置 C3P0 数据源 -->
<property name="hibernate.c3p0.max_size">10</property>
<property name="hibernate.c3p0.min_size">5</property>
<property name="c3p0.acquire_increment">2</property> <property name="c3p0.idle_test_period">2000</property>
<property name="c3p0.timeout">2000</property> <property name="c3p0.max_statements">10</property> <!-- 设定 JDBC 的 Statement 读取数据的时候每次从数据库中取出的记录条数 -->
<property name="hibernate.jdbc.fetch_size">100</property> <!-- 设定对数据库进行批量删除,批量更新和批量插入的时候的批次大小 -->
<property name="jdbc.batch_size">30</property> <!-- 需要关联的 hibernate 映射文件 .hbm.xml -->
<mapping resource="com/chen/many2many/Student.hbm.xml"/>
<mapping resource="com/chen/many2many/Teacher.hbm.xml"/> </session-factory>
</hibernate-configuration>
3、编写测试方法
HibernateTest.java
package com.chen.many2many; import java.util.Iterator;
import java.util.Set; import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder; public class HibernateTest {
private static SessionFactory sessionFactory;
private static Session session;
private static Transaction transaction; //定义事务初始化函数
public static void init(){
Configuration configuration = new Configuration().configure();
ServiceRegistry serviceRegistry =
new ServiceRegistryBuilder().applySettings(configuration.getProperties())
.buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry); session = sessionFactory.openSession();
transaction = session.beginTransaction();
} //定义事务结束时的处理函数
public static void doit(){
transaction.commit();
session.close();
sessionFactory.close();
} //编写自己的处理过程
public static void testSave(){
//学生: a,b,c
//教师:A,B
//所属关系A(a,b) B(a,b,c)
//初始化学生
Student a=new Student();
a.setStudentName("a");
Student b = new Student();
b.setStudentName("b");
Student c=new Student();
c.setStudentName("c");
//初始化老师
Teacher A=new Teacher();
A.setTeacherName("A");
Teacher B=new Teacher();
B.setTeacherName("B"); //设置关联关系
A.getStudentSet().add(a);
A.getStudentSet().add(b); B.getStudentSet().add(a);
B.getStudentSet().add(b);
B.getStudentSet().add(c); //保存
session.save(a);
session.save(b);
session.save(c);
session.save(A);
session.save(B);
}
public static void testGet(){
Teacher teacherResult=(Teacher) session.get(Teacher.class, 1);
System.out.println(teacherResult.getTeacherName());
Set<Student> set=teacherResult.getStudentSet();
for (Iterator iterator = set.iterator(); iterator.hasNext();) {
Student student = (Student) iterator.next();
System.out.println(student.getStudentName());
}
}
public static void main(String[] args) {
HibernateTest.init();
HibernateTest.testSave();
HibernateTest.testGet();
HibernateTest.doit();
System.out.println("完成---------");
} }
4、运行结果
数据表students
数据表teachers
中间表teachers_students
控制台显示结果:
三、多对多双向映射注意项
1、双向 n-n 关联需要两端都持有对方的一个集合对象引用。
2、双向n-n关联必须使用连接表。
3、集合属性应增加 key 子元素用以映射外键列, 集合元素里还应增加many-to-many子元素关联实体类。
4、在双向 n-n 关联的两边,都需指定连接表的表名及外键列的列名.。两个集合元素 set 的 table 元素的值必须指定,而且必须相同,这样就指定了同一张连接表。
5、set元素的两个子元素:key 和 many-to-many 都必须指定 column 属性,其中,key 和 many-to-many 分别指定本持久化类和关联类在连接表中的外键列名,因此两边的 key 与 many-to-many 的column属性交叉相同。也就是说,一边的set元素的key的 cloumn值为a,many-to-many 的 column 为b;则另一边的 set 元素的 key 的 column 值 b,many-to-many的
 column 值为 a。  
6、对于双向 n-n 关联, 必须把其中一端的 inverse 设置为 true, 否则两端都维护关联关系可能会造成主键冲突。
Hibernate表关系映射之多对多映射的更多相关文章
- Hibernate之关联映射(一对多和多对一映射,多对多映射)
		~~~接着之前的Hibernate框架接着学习(上篇面试过后发现真的需要学习以下框架了,不然又被忽悠让去培训.)~~~ 1:Hibernate的关联映射,存在一对多和多对一映射,多对多映射: 1.1: ... 
- Hibernate第六篇【多对多映射、一对一映射】
		前言 前面已经讲解了一对多和多对一的映射是怎么配置了,也讲解了inverse和cascade属性对关联关系的影响,本博文讲解多对多的映射和一对一的映射! 多对多映射 需求:一个项目由多个员工开发,一个 ... 
- Hibernate之关联关系映射(一对多和多对一映射,多对多映射)
		~~~接着之前的Hibernate框架接着学习(上篇面试过后发现真的需要学习一下框架了,不然又被忽悠让去培训.)~~~ 1:Hibernate的关联映射,存在一对多和多对一映射,多对多映射: 1.1: ... 
- Hibernate 中一对多和多对多映射
		1. 一对多映射 1.1 JavaWeb 一对多建表原则 多方表的外键指向一方表的主键; 1.2 编写一对多的 JavaBean // 客户(一方)和联系人(多方) // 客户(一方) JavaBea ... 
- Hibernate表关系映射之一对一映射
		一.数据表的映射关系 在数据库领域中,数据表和数据表之间关系一般可以分为如下几种: 一对一:比如公民和身份证的关系,一个人只有一张身份证,同时每张身份证也仅仅对应一个人! 一对多:比如客户和订单之间的 ... 
- hibernate(七)组件映射与多对一映射
		一.组件映射 用注解配置组件映射: Husband为我们映射的类,wife是这个类的一部分(属性不能与husband中属性重名,不要写Entity注解,不要有主键) Husband类:(在getWif ... 
- Hibernate表关系03
		一. 一对多映射 1.基本应用 1.1 准备项目 创建项目:hibernate-02-relation 引入jar,同前一个项目 复制实体(客户).映射.配置.工具类 1.2 创建订单表 表名: t_ ... 
- MyBatis学习(七)MyBatis关联映射之多对多映射
		对于数据库中的多对多关系建议使用一个中间表来维护关系. 1.创建四张表,分别为用户表,商品表,订单表,中间表. DROP TABLE IF EXISTS `t_user`; CREATE TABLE ... 
- Django框架表关系外键-多对多外键(增删改查)-正反向的概率-多表查询(子查询与联表查询)
		目录 一:表关系外键 1.提前创建表关系 2.目前只剩 书籍表和 书籍作者表没创建信息. 3.增 4.删 5.修改 二:多对多外键增删改查 1.给书籍绑定作者 2.删 3.修改 4.清空 三:正反向的 ... 
随机推荐
- xml文档绑定某个属性值到treeview算法
			原文发布时间为:2008-08-10 -- 来源于本人的百度文章 [由搬家工具导入] using System.Xml; protected void Button2_Click(object sen ... 
- Javascript 开启浏览器全屏模式
			作者:伯乐在线/前端空城师 通常在某些情况下,我们需要让浏览器开启全屏模式,以便获得更好的视觉体验,先看下全屏模式简单的几个API. 浏览器默认绑定 非全屏模式下, document的F11按键绑定开 ... 
- Django迁移数据库
			我们已经编写了博客数据库模型的代码,但那还只是 Python 代码而已,Django 还没有把它翻译成数据库语言,因此实际上这些数据库表还没有真正的在数据库中创建 为了让 Django 完成翻译,创建 ... 
- [原创][SW]TortoiseSVN创建本地版本控制
			1. 简介 TortoiseSVN是一个Windows平台下的Subversion用户端软件,以Windows shell extension的方式写成.它是自由软件,以GNU通用公共许可证发布.(f ... 
- java中正则表达式要进行转义的字符。
			/** * 转义正则特殊字符 ($()*+.[]?\^{},|) * * @param keyword * @return */public static String escapeExprSpeci ... 
- uitableview中文排序问题
			1,uitableview中涉及到排序的问题,查找资料后发现使用UILocalizedIndexedCollation可以很好处理中文和英文系统下中文的排序.而且如果第一个汉字首字母一样那么就会按照第 ... 
- 椭圆人头跟踪bmp图像序列 BMP Image Sequences for Elliptical Head Tracking
			BMP Image Sequences for Elliptical Head Tracking The BMP image sequences used in the head tracking d ... 
- 机器学习(十三)——机器学习中的矩阵方法(3)病态矩阵、协同过滤的ALS算法(1)
			http://antkillerfarm.github.io/ 向量的范数(续) 范数可用符号∥x∥λ表示. 经常使用的有: ∥x∥1=|x1|+⋯+|xn| ∥x∥2=x21+⋯+x2n−−−−−− ... 
- 转: svn服务器路径名修改(不需要全部重新拉取文件)
			svn路径名修改之后, 一大波的研发代码都可能面临变更.还有有一个svn relote神器 大家可以借助各自的SVN工具中哦relote命令完成路径的切换,而不需要全部重新download所有的新路径 ... 
- java.lang.String中的trim()方法的详细说明(转)
			String.Trim()方法到底为我们做了什么,仅仅是去除字符串两端的空格吗? 一直以为Trim()方法就是把字符串两端的空格字符给删去,其实我错了,而且错的比较离谱. 首先我直接反编译String ... 
