Hibernate关联关系中的CRUD之R

本文通过一对多双向关联映射的Teacher-Student实例,深入探讨Hibernate中的懒加载和急加载机制。当尝试在数据库关闭后访问关联对象时,会出现LazyInitializationException。通过设置FetchType.LAZY和FetchType.EAGER,可以控制加载关联表的行为。测试结果显示,不同的设置会影响查找的方向和是否关联加载另一方的数据。

以一对多的双向关联映射(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方法自己测试

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值