(二十九)hibernate 多对多
来源:互联网 发布:王坚阿里云博士别哭 编辑:程序博客网 时间:2024/06/08 11:43
多对多(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); //1t2.setStudents(ss); //1////s1.setTeachers(ts); //2//s2.setTeachers(ts); //2s = 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 多对多
- Hibernate 添加数据 二 (多对多)
- Hibernate中manytomany实例二(多对多单向)
- Hibernate 笔记二(多表设计之一对多)
- 深入浅出Hibernate(二)多对一关系映射
- hibernate初探之一对多映射(二)
- hibernate多对多
- hibernate多对多
- Hibernate多对多
- hibernate 多对多
- Hibernate多对多
- hibernate 多对多
- Hibernate多对多
- hibernate多对多
- Hibernate多对多
- hibernate 多对多
- Hibernate 多对多
- hibernate 多对多
- 关于“c语言从键盘输入字符串到指针数组”的问题
- [算法] 使用“复杂”的数据结构降低时间复杂度
- BZOJ1055:玩具取名(区间dp)
- Python 开发者的 6 个必备库
- centos 7 安装系统内核
- (二十九)hibernate 多对多
- maya(学习笔记)之Arnold材质
- Python 零碎知识
- Yum配置文件详解
- 2017.12.02.C语言总结
- Java 多线程 学习笔记
- maya(学习笔记)之Arnold节点
- 《弃子长安》第十六章 道阳心经
- 将矩阵a转置后存放到矩阵b当中