以一对多的双向关联映射(Teacher——Student)作为实例
其Teacher类和Student类分别为:
package com.model;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToMany;
@Entity
public class Teacher {
private int id;
private String name;
private Set<Student> students = new HashSet<Student>();
@Id
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;
}
@OneToMany(mappedBy="teacher")
public Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
}package com.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
@Entity
public class Student {
private int id;
private String name;
private Teacher teacher;
@Id
@GeneratedValue
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;
}
@ManyToOne
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
}
hibernate配置文件为:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- 连接的数据库驱动 -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- 连接的数据库的url -->
<property name="connection.url">jdbc:mysql://localhost:3306/hibernate</property>
<!-- 连接的数据库的用户名-->
<property name="connection.username">root</property>
<!-- 连接的数据库的密码 -->
<property name="connection.password"></property>
<!-- 配置Hibernate数据库方言 -->
<property name="Dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 输出执行的SQL语句 -->
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<!-- 启动时撤销并重新创建数据库的模式-->
<property name="hbm2ddl.auto">update</property>
<property name="current_session_context_class">thread</property>
<mapping class="com.model.Teacher"/>
<mapping class="com.model.Student"/>
</session-factory>
</hibernate-configuration>
已有表结构为:

测试类1:
package com.test;
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;
import org.junit.Test;
import com.model.Student;
import com.model.Teacher;
public class ORMappingTest {
@Test
public void test() {
Configuration cfg = new Configuration();
cfg.configure();
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(cfg.getProperties()).buildServiceRegistry();
SessionFactory sessionFactory = cfg.buildSessionFactory(serviceRegistry);
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Teacher t = (Teacher) session.get(Teacher.class, 0);
for(Student s:t.getStudents()) {
System.out.println(s.getName());
}
transaction.commit();
sessionFactory.close();
}
}
测试类1的结果:
Hibernate:
select
teacher0_.id as id0_0_,
teacher0_.name as name0_0_
from
Teacher teacher0_
where
teacher0_.id=?
Hibernate:
select
students0_.teacher_id as teacher3_0_1_,
students0_.id as id1_,
students0_.id as id1_0_,
students0_.name as name1_0_,
students0_.teacher_id as teacher3_1_0_
from
Student students0_
where
students0_.teacher_id=?
s2
s1
----------一对多查找时默认分别查找一和多两个方向的表--------
此时,若修改测试类1为:
Teacher t = (Teacher) session.get(Teacher.class, 0);
transaction.commit();
for(Student s:t.getStudents()) {
System.out.println(s.getName());
}
则会报org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.model.Teacher.students, no session or session was closed
因为Teacher对象的get方法默认仅仅加载本表的内容,只有需要多那方向的内容时才会查找另一方向的表,在数据库关闭后再去访问Student表的内容肯定出错。
------------若设置Teacher类为:
@OneToMany(mappedBy="teacher",fetch=FetchType.EAGER)
public Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
则测试类1的结果为:
Hibernate:
select
teacher0_.id as id0_1_,
teacher0_.name as name0_1_,
students1_.teacher_id as teacher3_0_3_,
students1_.id as id3_,
students1_.id as id1_0_,
students1_.name as name1_0_,
students1_.teacher_id as teacher3_1_0_
from
Teacher teacher0_
left outer join
Student students1_
on teacher0_.id=students1_.teacher_id
where
teacher0_.id=?
s2
s1
----------此时查找的是一这方向的表并关联多那方向的表-------
测试类2:
Student s = (Student) session.get(Student.class, 1);
System.out.println(s.getTeacher().getName());
transaction.commit();
测试类2的结果:
Hibernate:
select
student0_.id as id1_1_,
student0_.name as name1_1_,
student0_.teacher_id as teacher3_1_1_,
teacher1_.id as id0_0_,
teacher1_.name as name0_0_
from
Student student0_
left outer join
Teacher teacher1_
on student0_.teacher_id=teacher1_.id
where
student0_.id=?
t
----------多对一查找时默认会查找多这方向的表并关联一方向的表-------
此时,若修改测试类2为:
Student s = (Student) session.get(Student.class, 1);
transaction.commit();
System.out.println(s.getTeacher().getName());
----------仍然输出相同的结果,因为在Student对象的get方法时就已经将两个关联表的内容加载至内存,即使数据库关闭仍能通过访问内存得到结果。
----------若设置Student类为:
@ManyToOne(fetch=FetchType.LAZY)
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
则测试类2的结果为:
Hibernate:
select
student0_.id as id1_0_,
student0_.name as name1_0_,
student0_.teacher_id as teacher3_1_0_
from
Student student0_
where
student0_.id=?
Hibernate:
select
teacher0_.id as id0_0_,
teacher0_.name as name0_0_
from
Teacher teacher0_
where
teacher0_.id=?
t
----------此时查找的是分别查找多这方向的表和一那方向的表-------
-----------------------------------------------------------------------------------------
可通过设置@ManyToOne(fetch=FetchType.LAZY)和fetch=FetchType.EAGER来设置懒加载和勤加载。
-----------------------------------------------------------------------------------------
load方法自己测试
本文通过一对多双向关联映射的Teacher-Student实例,深入探讨Hibernate中的懒加载和急加载机制。当尝试在数据库关闭后访问关联对象时,会出现LazyInitializationException。通过设置FetchType.LAZY和FetchType.EAGER,可以控制加载关联表的行为。测试结果显示,不同的设置会影响查找的方向和是否关联加载另一方的数据。

1067

被折叠的 条评论
为什么被折叠?



