hibernate一对多单向和双向映射配置实例源码说明,一对多单向和双向映射。
一、hibernate一对多单向关联
hibernate中多对一和一对多类似
一对多映射中,只需要在一方的POJO中加入Set.
在一方的映射中加入:
<set name=”students”>
<key column=”class_id”></key>
<one-to-many/>
</set>
有指示作用,指示在多方的表中加入一个外键.
- Hibernate一对多单向关联映射
- hibernate这种映射的本质是利用了多对一的关联映射的原理
- 多对一关联映射:是在多的一端添加一个外键维护多指向一的关联引用
- 一对多关联映射:是在多的一端添加一个外键维护一指向多的关联引用
- 一对多和多对一的映射策略是一致的,只是站的角度不同
- 缺点:
- * 更新student表中的classesid字段时,需要对每一个student发出一个update的sql,
- 来更新classesid字段
- * 如果将t_student表中的classesis设置为非空,则不能保存student数据,因为关系是由
- classes维护的,在保存student时,还没有对应的classesid被生成
具体实例代码如下:
- package com.lwf.hibernate.pojo;
- import java.util.HashSet;
- import java.util.Set;
- public class Classes {
- private int id;
- private String name;
- private Set students = new HashSet();
- public int getId() {
- return id;
- }
- public void setId(int id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public Set getStudents() {
- return students;
- }
- public void setStudents(Set students) {
- this.students = students;
- }
- }
- package com.lwf.hibernate.pojo;
- public class Student {
- private int id;
- private String name;
- private int age;
- public int getId() {
- return id;
- }
- public void setId(int id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- }
Classes.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.lwf.hibernate.pojo”>
- <class name=”Classes” table=”t_classes”>
- <id name=”id”>
- <generator class=”native”/>
- </id>
- <property name=”name”/>
- <set name=”students” >
- <key column=”class_id” ></key>
- <one-to-many class=”Student” />
- </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.lwf.hibernate.pojo”>
- <class name=”Student” table=”t_student”>
- <id name=”id”>
- <generator class=”native”/>
- </id>
- <property name=”name”/>
- <property name=”age”/>
- </class>
- </hibernate-mapping>
具体的数据库结构实例:
- mysql> desc student;
- +———-+————–+——+—–+———+—————-+
- | Field | Type | Null | Key | Default | Extra |
- +———-+————–+——+—–+———+—————-+
- | id | int(11) | NO | PRI | NULL | auto_increment |
- | name | varchar(255) | YES | | NULL | |
- | class_id | int(11) | YES | MUL | NULL | |
- +———-+————–+——+—–+———+—————-+
- 3 rows in set (0.06 sec)
- mysql> desc t_class;
- +——-+————–+——+—–+———+—————-+
- | Field | Type | Null | Key | Default | Extra |
- +——-+————–+——+—–+———+—————-+
- | id | int(11) | NO | PRI | NULL | auto_increment |
- | name | varchar(255) | YES | | NULL | |
- +——-+————–+——+—–+———+—————-+
测试方法:
- package com.lwf.hibernate.test;
- import java.util.HashSet;
- import java.util.Iterator;
- import java.util.Set;
- import junit.framework.TestCase;
- import org.hibernate.Session;
- import com.lwf.hibernate.pojo.Classes;
- import com.lwf.hibernate.pojo.Student;
- import com.lwf.hibernate.util.HibernateUtil;
- public class One2Many_Test extends TestCase{
- //从classes这一端来维护,即在单方维护,会产生insert和update语句.
- public void testClasses(){
- Session session = HibernateUtil.getSession();
- session.beginTransaction();
- try{
- Set students = new HashSet();
- for(int i=0;i<5;i++){
- Student s = new Student();
- s.setName(“name” + i);
- s.setAge((10 + i));
- students.add(s);
- session.save(s);
- }
- Classes cla = new Classes();
- cla.setName(“class1″);
- cla.setStudents(students);
- session.save(cla);
- //先保存,最后根据class_id更新Student
- HibernateUtil.commit(session);
- }catch(Exception e){
- HibernateUtil.roolback(session);
- }finally{
- HibernateUtil.closeSession(session);
- }
- }
- public void testLoad(){
- Session session = HibernateUtil.getSession();
- session.beginTransaction();
- try{
- Classes s = (Classes)session.load(Classes.class, 1);
- Set student = s.getStudents();
- for (Iterator iterator = student.iterator(); iterator.hasNext();) {
- Student stu = (Student) iterator.next();
- System.out.println(stu.getName());
- }
- HibernateUtil.commit(session);
- }catch(Exception e){
- HibernateUtil.roolback(session);
- }finally{
- HibernateUtil.closeSession(session);
- }
- }
- }
注意保存生成的hibernate语句:
- Hibernate: insert into t_student (name, age) values (?, ?)
- Hibernate: insert into t_student (name, age) values (?, ?)
- Hibernate: insert into t_student (name, age) values (?, ?)
- Hibernate: insert into t_student (name, age) values (?, ?)
- Hibernate: insert into t_student (name, age) values (?, ?)
- Hibernate: insert into t_classes (name) values (?)
- Hibernate: update t_student set class_id=? where id=?
- Hibernate: update t_student set class_id=? where id=?
- Hibernate: update t_student set class_id=? where id=?
- Hibernate: update t_student set class_id=? where id=?
- Hibernate: update t_student set class_id=? where id=?
先保存student,再保存classes最后根据classes的id更新student的class_id
这实际上是由classes这方来维护两者的关联关系.
正常情况下关系应该由多的一方来维护,在双向关联中我们从多方来维护两者的关系.这样就可以避免update语句的出现.而是直接insert即可.
二、一对多双向关联
下面我们看看双向的一对多映射,实际上就是把一对多与多对一结合起来看.
- Hibernate 一对多双向关联映射
- 一对多双向关联映射的方法:
- 在一一端:
- 在集合标签里面使用<key>标签来表明需要在对方的表中添加一个外键指向一一端。
- 在多一端:
- 使用<many-to-one>标签来映射。
- 需要注意:<key>标签所指定的外键字段名需要与<many-to-one>标签定义的外键字段名一致,否则便会造成引用数据的
- 丢失!
- ————————————————————————————–
- 如果从一端来维护一对多双向关联的关系,hibernate会发出多余的update语句,所以
- 一般地情况下,我们便会从多一端来维护其关联关系!
- ----------------------------------------------------
在单向映射的基础上加上多对一关联即可.更改的文件:
- package com.lwf.hibernate.pojo;
- public class Student {
- private int id;
- private String name;
- private int age;
- private Classes classes;
- public int getId() {
- return id;
- }
- public void setId(int id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- public Classes getClasses() {
- return classes;
- }
- public void setClasses(Classes classes) {
- this.classes = classes;
- }
- }
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.lwf.hibernate.pojo”>
- <class name=”Student” table=”t_student”>
- <id name=”id”>
- <generator class=”native”/>
- </id>
- <property name=”name”/>
- <property name=”age”/>
- <many-to-one name=”classes” column=”class_id”></many-to-one>
- </class>
- </hibernate-mapping>
即从Student的角度就是多对一,而从Classes角度就是一对多.
此时的表结构与单向的时候是一样的.
- package com.lwf.hibernate.test;
- import java.util.HashSet;
- import java.util.Iterator;
- import java.util.Set;
- import junit.framework.TestCase;
- import org.hibernate.Session;
- import com.lwf.hibernate.pojo.Classes;
- import com.lwf.hibernate.pojo.Student;
- import com.lwf.hibernate.util.HibernateUtil;
- public class One2Many_Test extends TestCase{
- //从classes这一端来维护,即在单方维护,会产生insert和update语句.
- public void testClasses(){
- Session session = HibernateUtil.getSession();
- session.beginTransaction();
- try{
- Set students = new HashSet();
- for(int i=0;i<5;i++){
- Student s = new Student();
- s.setName(“name” + i);
- s.setAge((10 + i));
- students.add(s);
- session.save(s);
- }
- Classes cla = new Classes();
- cla.setName(“class1″);
- cla.setStudents(students);
- session.save(cla);
- //先保存,最后根据class_id更新Student
- HibernateUtil.commit(session);
- }catch(Exception e){
- HibernateUtil.roolback(session);
- }finally{
- HibernateUtil.closeSession(session);
- }
- }
- //由于配置了双向关联,所以下面先保存了classes再保存student只有insert语句,没有update语句
- public void testStudent(){
- Session session = HibernateUtil.getSession();
- session.beginTransaction();
- try{
- Classes cla = new Classes();
- cla.setName(“class111″);
- session.save(cla);
- for (int i = 0; i < 5; i++) {
- Student s = new Student();
- s.setName(“name111″+i);
- s.setClasses(cla);
- session.save(s);
- }
- HibernateUtil.commit(session);
- }catch(Exception e){
- HibernateUtil.roolback(session);
- }finally{
- HibernateUtil.closeSession(session);
- }
- }
- //从classes得到student,主要测试单向关联
- public void testLoadClass(){
- Session session = HibernateUtil.getSession();
- session.beginTransaction();
- try{
- Classes s = (Classes)session.load(Classes.class, 1);
- Set student = s.getStudents();
- for (Iterator iterator = student.iterator(); iterator.hasNext();) {
- Student stu = (Student) iterator.next();
- System.out.println(stu.getName());
- }
- HibernateUtil.commit(session);
- }catch(Exception e){
- HibernateUtil.roolback(session);
- }finally{
- HibernateUtil.closeSession(session);
- }
- }
- //从student得到classes,配置了双向关联后的测试
- public void testLoadStudent(){
- Session session = HibernateUtil.getSession();
- session.beginTransaction();
- try{
- Student s = (Student)session.load(Student.class, 1);
- System.out.println(s.getName());
- System.out.println(s.getClasses().getName());
- HibernateUtil.commit(session);
- }catch(Exception e){
- HibernateUtil.roolback(session);
- }finally{
- HibernateUtil.closeSession(session);
- }
- }
- }
主要区别:
由于配置了双向关联,所以下面先保存了classes再保存student只有insert语句,没有update语句
以下是testStudent方法产生的SQL语句
- Hibernate: insert into t_classes (name) values (?)
- Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)
- Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)
- Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)
- Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)
- Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)
三、下面讨论一下关于INVERSE的用法:
- 关于inverse属性:
- inverse属性可以被设置到集合标签<set>上,表示在存储双向一对多关联映射的时候,
- 存储的是那一方的关联引用。默认情况下,inverse=“false”,所以,我们可以从一一端
- 或者多一端来维护两者之间的关系;如果我们设置inverse=“true”,则只能通过多一端来
- 维护两者之间的关系。inverse属性可以被用在一对多和多对多双向关联中;
- 注意:inverse属性只是在将数据持久化到数据库的过程中发挥作用.
主要看看上面双向关联中testClasses方法,当classes.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.lwf.hibernate.pojo”>
- <class name=”Classes” table=”t_classes”>
- <id name=”id”>
- <generator class=”native”/>
- </id>
- <property name=”name”/>
- <set name=”students” >
- <key column=”class_id” ></key>
- <one-to-many class=”Student” />
- </set>
- </class>
- </hibernate-mapping>
我们知道上面的testClasses方法产生的sql语句是先insert再update,上面已经讲到是从一方来维护关联关系的.那么现在我们把classes.hbm.xml的set上面增加inverse=”true”即
- <set name=”students” inverse=”true”>
- <key column=”class_id” ></key>
- <one-to-many class=”Student” />
- </set>
那么这时候testClasses方法产生的SQL语句是?
- Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)
- Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)
- Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)
- Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)
- Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)
- Hibernate: insert into t_classes (name) values (?)
虽然只产生了insert语句,但因为t_classes插入语句在后,所以数据库里面对应的t_student的记录:
- mysql> select * from t_student;
- +—-+——-+——+———-+
- | id | name | age | class_id |
- +—-+——-+——+———-+
- | 1 | name0 | 10 | NULL |
- | 2 | name1 | 11 | NULL |
- | 3 | name2 | 12 | NULL |
- | 4 | name3 | 13 | NULL |
- | 5 | name4 | 14 | NULL |
- +—-+——-+——+———-+
显然class_id为空.没有更新.
即用了INVERSE,将强制要求从多的一方来维护关系.即当设置了INVERSE属性后,要求使用testStudent方法来做保存.
而INVERSE属性没有设置时,对于双向的一对多关联,我们即可以使用testClasses又可以使用testStudent方法进行保存,但是他们的区别是testClasses操作中有insert和update语句,而testStudent只有insert语句.显然使用testStudent即从多方来维护关联关系节约了资源...
- hibernate_one2many.rar (11.9 KB)
- 下载次数: 14
- hibernate_one2many_double.rar (12.8 KB)
- 下载次数: 13