hibernate 多对多(many-to-many)
多对多(many-to-many):在操作和性能方面都不太理想,所以多对多的映射使用较少,实际使用中最好转换成一对多的对象模型;hibernate会为我们创建中间关联表,转换成两个一对多。
1. E-R图

2. 实体类:
Teacher实体类如下:
- package com.reiyen.hibernate.domain;
- import java.util.Set;
- public class Teacher {
- private int id;
- private String name;
- private Set<Student> students;
- //setter和getter方法
- }
Student实体类如下:
- package com.reiyen.hibernate.domain;
- import java.util.Set;
- public class Student {
- private int id;
- private String name;
- private Set<Teacher> teachers;
- //setter和getter方法
- }
3.映射文件如下:
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">
- <hibernate-mapping package="com.reiyen.hibernate.domain">
- <class name="Teacher">
- <id name="id">
- <generator class="native" />
- </id>
- <property name="name" />
- <!-- 通过table项告诉hibernate中间表的名称 -->
- <set name="students" table="teacher_student">
- <!-- 通过key属性告诉hibernate在中间表里面查询teacher_id值相应的teacher记录 -->
- <key column="teacher_id" />
- <!-- 通过column项告诉hibernate对student表中查找student_id值相就的studnet记录 -->
- <many-to-many class="Student" column="student_id" />
- </set>
- </class>
- </hibernate-mapping>
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">
- <hibernate-mapping package="com.reiyen.hibernate.domain">
- <class name="Student" >
- <id name="id" >
- <generator class="native" />
- </id>
- <property name="name" />
- <set name="teachers" table="teacher_student">
- <key column="student_id" />
- <many-to-many class="Teacher" column="teacher_id"/>
- </set>
- </class>
- </hibernate-mapping>
一定要注意映射文件中<many-to-many class="Teacher" column="teacher_id"/>中class的值,它必须与你另一个关联映射文件中的class属性的name值一致,其实就是与你的实体类的类名一致,如:<many-to-many class="Teacher" column="teacher_id"/>中class的值就不能写成"teacher"。如果写成这样的话,就会抛出如下异常:An association
from the table teacher_student refers to an unmapped class: com.reiyen .hibernate.domain.teacher
4. 测试程序如下:
- public class Many2Many {
- public static void main(String[] args) {
- add();
- //query(1);
- }
- static void query(int id) {
- Session s = null;
- Transaction tx = null;
- try {
- s = HibernateUtil.getSession();
- tx = s.beginTransaction();
- Teacher t = (Teacher) s.get(Teacher.class, id);
- System.out.println("students:" + t.getStudents().size());
- tx.commit();
- } finally {
- if (s != null)
- s.close();
- }
- }
- static void add() {
- Session s = null;
- Transaction tx = null;
- try {
- Set<Teacher> ts = new HashSet<Teacher>();
- Teacher t1 = new Teacher();
- t1.setName("t1 name");
- ts.add(t1);
- Teacher t2 = new Teacher();
- t2.setName("t2 name");
- ts.add(t2);
- Set<Student> ss = new HashSet<Student>();
- Student s1 = new Student();
- s1.setName("s1");
- ss.add(s1);
- Student s2 = new Student();
- s2.setName("s2");
- ss.add(s2);
- t1.setStudents(ss); //1
- t2.setStudents(ss); //1
- //
- // s1.setTeachers(ts); //2
- // s2.setTeachers(ts); //2
- s = HibernateUtil.getSession();
- tx = s.beginTransaction();
- s.save(t1);
- s.save(t2);
- s.save(s1);
- s.save(s2);
- tx.commit();
- } finally {
- if (s != null)
- s.close();
- }
- }
- }
运行此程序后:控制台打印的sql语句如下所示:
Hibernate: insert into Teacher (name) values (?)
Hibernate: insert into Teacher (name) values (?)
Hibernate: insert into Student (name) values (?)
Hibernate: insert into Student (name) values (?)
Hibernate: insert into teacher_student (teacher_id, student_id) values (?, ?)
Hibernate: insert into teacher_student (teacher_id, student_id) values (?, ?)
Hibernate: insert into teacher_student (teacher_id, student_id) values (?, ?)
Hibernate: insert into teacher_student (teacher_id, student_id) values (?, ?)
一共在中间表里面插入了4条记录。
中间表结构如下所示:
DROP TABLE IF EXISTS `test`.`teacher_student`;
CREATE TABLE `test`.`teacher_student` (
`teacher_id` int(11) NOT NULL,
`student_id` int(11) NOT NULL,
PRIMARY KEY (`student_id`,`teacher_id`),
KEY `FK2E2EF2DE6C8A2663` (`teacher_id`),
KEY `FK2E2EF2DE5BEEDBC3` (`student_id`),
CONSTRAINT `FK2E2EF2DE5BEEDBC3` FOREIGN KEY (`student_id`) REFERENCES `student` (`id`),
CONSTRAINT `FK2E2EF2DE6C8A2663` FOREIGN KEY (`teacher_id`) REFERENCES `teacher` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
表中插入的记录如下所示:
mysql> select * from teacher_student;
+------------+------------+
| teacher_id | student_id |
+------------+------------+
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
| 2 | 2 |
+------------+------------+
4 rows in set (0.00 sec)
程序中注释为1的语句非常重要,它是建立Teacher与Student关联的语句,如果没有这两条语句,虽然程序照样会执行,但是在中间表teacher_student没有任何记录,也就是Teacher与Student之间未关联。
当然你也可以通过程序中注释为2的语句来建立Teacher与Student之间的关联关系,同样会产生与注释为1的语句的效果。但是你不能在程序中同时出现以上四句程序,否则会抛出异常( PRIMARY KEY (`student_id`,`teacher_id`),所以会出现主键冲突的异常),:
Hibernate: insert into teacher_student (teacher_id, student_id) values (?, ?)
Hibernate: insert into teacher_student (teacher_id, student_id) values (?, ?)
Hibernate: insert into teacher_student (teacher_id, student_id) values (?, ?)
Hibernate: insert into teacher_student (teacher_id, student_id) values (?, ?)
Hibernate: insert into teacher_student (student_id, teacher_id) values (?, ?)
Hibernate: insert into teacher_student (student_id, teacher_id) values (?, ?)
Hibernate: insert into teacher_student (student_id, teacher_id) values (?, ?)
Hibernate: insert into teacher_student (student_id, teacher_id) values (?, ?)
Exception in thread "main" org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
解决上面产生异常的办法是设置inverse属性。即在Tearcher一端或Student一端设置inverse="true",即让他们之中的某一方放弃维护关联关系。此时,虽然上面四句程序在测试程序中同时出现了(其实就是在对象模型上相互设置了他们的关联关系),但程序照样能运行正常,因为了在数据库模型上,只会有两句程序生效,也就是没有设置inverse="true"的那一端会去维护关联关系。有关inverse的说细信息,可以参看我的文章hibernate级联(cascade和inverse).
执行测试程序中的查询测试,控制台打印的信息如下所示:
Hibernate: select teacher0_.id as id5_0_, teacher0_.name as name5_0_ from Teacher teacher0_ where teacher0_.id=?
Hibernate: select students0_.teacher_id as teacher1_1_, students0_.student_id as student2_1_, student1_.id as id7_0_, student1_.name as name7_0_ from teacher_student students0_ left outer join Student student1_ on students0_.student_id=student1_.id where students0_.teacher_id=?
students:2
从打印出的sql语句可以看出,多对多关系进行查询时,效率是比较低的。
hibernate 多对多(many-to-many)的更多相关文章
- hibernate多对多关联映射
关联是类(类的实例)之间的关系,表示有意义和值得关注的连接. 本系列将介绍Hibernate中主要的几种关联映射 Hibernate一对一主键单向关联Hibernate一对一主键双向关联Hiberna ...
- hibernate多对一双向关联
关联是类(类的实例)之间的关系,表示有意义和值得关注的连接. 本系列将介绍Hibernate中主要的几种关联映射 Hibernate一对一主键单向关联Hibernate一对一主键双向关联Hiberna ...
- hibernate多对一单向关联
关联是类(类的实例)之间的关系,表示有意义和值得关注的连接. 本系列将介绍Hibernate中主要的几种关联映射 Hibernate一对一主键单向关联Hibernate一对一主键双向关联Hiberna ...
- Hibernate多对多关系映射(建表)
下边讲述Hibernate多对多关系映射. 多对多关系的表的结构为: 两个实体表,还包含一个关系表,关系表为复合主键,如果要使用Hibernate多对多关系映射,则关系表必须只包含两个字段,如果生成了 ...
- atitit.atitit.hb many2one relate hibernate 多对一关联配置..
atitit.atitit.hb many2one relate hibernate 多对一关联配置.. 1. 多对一单向 @ManyToOne 1 1. 其中@JoinColumn 注解 2 2. ...
- hibernate 多对多
HibernateHibernate多对多关联映射通常别拆分成两个多对一关联映射1. 下面的HostBean.UserBean.UserHostBean,UserHostBean是两个表之间的关联表, ...
- hibernate多对一单向外键
hibernate多对一单向外键: 描述:
- Hibernate多对一ManytoOne
------------------------Hibernate多对一ManytoOne 要点: ManytoOne配置在多端 可以配置级联操作 @ManyToOne(cascade=Cascade ...
- hibernate 多对多一个对象出现多条记录问题
hibernate 多对多时,当须要依据它关联的对象查找的时候,会出现一个对象有多条记录的问题 用 left join fetch 抓取查询的时候还是会出现这问题,是由于主表在关联表中有多条记录 用 ...
- Hibernate多对多操作
---------------------siwuxie095 Hibernate 多对多操作 以用户和角色为例 (一)多对多映射配置 第一步:创建两个实体类,用户和角色 第二步:让两个实体类之间互相 ...
随机推荐
- form前台提交List<Object>对象以及后台处理
页面: <form method="post" action="test.do" id="form"> <input ty ...
- 外部类与main方法笔记
外部类 1. 外部public class只能有一个 2. 外部类只能有两种访问控制级别: public 和默认 3. 一个文件中,可以有多个public class,即外部类为public,还可以有 ...
- C语言中 ln(以自然对数e为底) lg(以十为底) 以及logab(以a为底,b为真数)的相关知识
总所周知,我们在高中学过对数函数,记作y=logax.下面是百度百科关于对数函数的描述: 对数的定义:一般地,如果ax=N(a>0,且a≠1),那么数x叫做以a为底N的对数,记作x=logaN, ...
- angularjs实现星星评分
angularjs实现星星评分 自定义指令 app.directive('myStars', function () { return { require : '?ngModel', // ?ngMo ...
- JQuery小知识点代码
1.链式操作 $(function(){ /*var oDiv = $('#div1'); oDiv.html('hello'); oDiv.css('background','red'); oDiv ...
- 如果在applicationContext.xml中没有配置bean的属性,那么也会导致空指针异常
报错如下: java.lang.NullPointerException cn.itcast.action.VisitAction.toAddPage(VisitAction.java:37) sun ...
- 使用 <!-- 指定使用hibernate核心配置文件 --> <property name="configLocations" value="classpath:hibernate.cfg.xml"></property>
在bean.xml文件中,这样使用出现问题 <!-- 指定使用hibernate核心配置文件 --> <property name="configLocations&quo ...
- ps(笔记)
窗口 工作区 默认窗口(恢复) ctrl + n 点阵图(像素图) 小方格组成的 alt 键 配合 放大缩小 ppi dpi 打印输出. 画布新建 z键 局部放大 右击实际像素操作 f键 全屏 空格键 ...
- angularjs笔记(1)
https://github.com/angular/angular.js/blob/master/src/ng/q.js 1.ng-app 指令告诉 AngularJS,<div> 元素 ...
- Java动态代理的总结
最近和一个好友在聊起Mybatis时,他问用Mybatis我们只是配置好mapper,然后写dao层接口就实现了dao层方法.然后我说我觉得用动态代理可以实现.然后他又说感觉动态代理和外观模式没什么区 ...