本次以Teacher和Student为例
一对多关联映射:有单向一对多关联映射和双向一对多关联映射
一对多关联映射和多对一关联映射映射原理是一致的,都是在多的一端加入一个外键,指向一的一端
它们的区别在于维护的关系不同:
- 多对一维护的关系是:多指向一的关系,有了此关系,在加载多的时候可以将一加载上来
- 一对多维护的关系是:一指向多的关系,有了此关系,在加载一的时候可以将多加载上来
在一的一端维护关系存在缺陷:
- 因为多的一端Student不知道Teacher的存在(也就是Student没有维护与Teache的关系)所以在保存Student的时候关系字段teacherid是为null的,如果将该关系字段设置为非空,则将无法保存数据
- 另外因为Student不维护关系,而Teacher维护关系,Teacher就会发出多余的update语句,保证Teacher和Student有关系,这样加载Teacher的时候才可以把该Teacher对应的学生加载上来
单向关联映射:
实体类:
Teacher.java
package com.java.hibernate;
import java.util.Set;
public class Teacher {
private int id;
private String name;
private Set<Student> students;
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<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
}
Student.javapackage com.java.hibernate;
public class Student {
private int id;
private String name;
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;
}
}
实体类映射文件: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>
<class name="com.java.hibernate.Teacher" table="t_teacher">
<id name="id">
<generator class="native" />
</id>
<property name="name" />
<set name="students">
<key column="teacherid"/>
<one-to-many class="com.java.hibernate.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>
<class name="com.java.hibernate.Student" table="t_student">
<id name="id">
<generator class="native"></generator>
</id>
<property name="name"></property>
</class>
</hibernate-mapping>
测试类:Test.java
双向关联映射:
package com.java.hibernate;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import junit.framework.TestCase;
import org.hibernate.Session;
public class Test extends TestCase{
public void testSave1() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Student student1 = new Student();
student1.setName("张三");
Student student2 = new Student();
student2.setName("李四");
Teacher teacher = new Teacher();
teacher.setName("周杰伦");
Set<Student> students = new HashSet<Student>();
students.add(student1);
students.add(student2);
teacher.setStudents(students);
//抛出TransientObjectException
//因为Student不是Persistent状态的对象,它是Transient状态的对象
session.save(students);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally {
HibernateUtils.closeSession(session);
}
}
public void testSave2() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Student student1 = new Student();
student1.setName("张三");
session.save(student1);
Student student2 = new Student();
student2.setName("李四");
session.save(student2);
Teacher teacher = new Teacher();
teacher.setName("周杰伦");
Set<Student> students = new HashSet<Student>();
students.add(student1);
students.add(student2);
teacher.setStudents(students);
//可以成功保存数据
//但是会发出多余的update语句来维持关系
session.save(teacher);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally {
HibernateUtils.closeSession(session);
}
}
public void testLoad() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Teacher teacher = (Teacher) session.load(Teacher.class, 1);
System.out.println(teacher.getName());
Set<Student> students = teacher.getStudents();
for (Iterator iter = students.iterator(); iter.hasNext();) {
Student student = (Student) iter.next();
System.out.println(student.getName());
}
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally {
HibernateUtils.closeSession(session);
}
}
}<span style="color:#ff0000;">
</span>
双向关联映射:
采用一对多双向关联映射的目的主要是为了解决一对多单向关联的缺陷,而不是需求驱动的。
一对多双向关联映射的映射方式:
- 在一的一端的集合上采用<key>标签,在多的一端加入一个外键
- 在多的一端采用<many-to-one>标签
注意:<key>标签和<many-to-one>标签加入的字段保持一直,否则会产生数据混乱
实体类:
Teacher.java
package com.java.hibernate;
import java.util.Set;
public class Teacher {
private int id;
private String name;
private Set<Student> students;
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<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
}
Student.java
package com.java.hibernate;
public class Student {
private int id;
private String name;
private Teacher teacher;
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
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;
}
}
实体类映射文件:
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>
<class name="com.java.hibernate.Teacher" table="t_teacher">
<id name="id">
<generator class="native" />
</id>
<property name="name" />
<set name="students">
<key column="studentid"/>
<one-to-many class="com.java.hibernate.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>
<class name="com.java.hibernate.Student" table="t_student">
<id name="id">
<generator class="native"></generator>
</id>
<property name="name"></property>
<many-to-one name="teacher" column="studentid" />
</class>
</hibernate-mapping>
测试类:
Test.java
package com.java.hibernate;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import junit.framework.TestCase;
import org.hibernate.Session;
public class Test extends TestCase {
public void testSave() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Student student1 = new Student();
student1.setName("张三");
session.save(student1);
Student student2 = new Student();
student2.setName("李四");
session.save(student2);
Set<Student> students = new HashSet<Student>();
students.add(student1);
students.add(student2);
Teacher teacher = new Teacher();
teacher.setName("周杰伦");
teacher.setStudents(students);
session.save(teacher);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally {
HibernateUtils.closeSession(session);
}
}
public void testLoad() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Student student = (Student) session.load(Student.class, 1);
System.out.println(student.getName());
System.out.println(student.getTeacher().getName());
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally {
HibernateUtils.closeSession(session);
}
}
}