提纲:
- lazy的概念和为什么
- 什么时候用lazy
- 当前实体类
- 与当前实体类关联的实体类
- 关联多个实体:一对多,多对多
- 关联单个实体:一对一,多对一
- 各标签上的lazy取值
- 多对多测试
- 一对一测试
lazy的概念和为什么
Hibernate 的延迟加载(lazy load)是一个被广泛使用的技术。这种延迟加载保证了应用只有在需要时才去数据库中抓取相应的记录。通过延迟加载技术可以避免过多、过早地加载数据表里的数据,从而降低应用的内存开销。Hibernate 的延迟加载本质上就是代理模式的应用,当程序通过 Hibernate 装载一个实体时,默认情况下,Hibernate 并不会立即抓取它的集合属性、关联实体所以对应的记录,而是通过生成一个代理来表示这些集合属性、关联实体,这就是代理模式应用带来的优势。
什么时候用lazy
主要是两个地方使用:
- 当前实体类加载
- 和当前实体类关联的实体类或者实体类集合加载时
第一个种容易理解,就是一个实体类,从数据库中查询了一条记录,在还没有实际使用的时候,不会真正的去数据库查询,采用代理假装已经查到了。
第二种是当前实体类延迟已经设置好,那和当前实体类关联的实体类或者实体类集合如何加载呢,如果关联的实体类集合数据量比较巨大,总不能一次性全部加载吧,所以也需要延迟加载。
所以总结出来就是,看当前用的实体类(当前也可能是实体类集合,多条记录嘛),再关注一下和这个实体类关联的那些实体类或实体类集合。
各标签上的lazy取值
上面已经讲解了主要的应用场景,那具体怎么设置呢,也就是当前实体类和关联实体类(集合)的延迟具体怎么设置?!
标签 | 取值范围 | 解决问题 |
---|---|---|
class | true/false | 当前实体类 |
set/list | true/false/extra | 关联实体类(集合) |
one-to-one/many-to-one | false/proxy/no-proxy | 关联实体类(集合) |
property标签也可以设置lazy属性,但是不怎么用,我也不会用!
多对多测试
实体类classes.java
package entity;
import java.util.Set;
/**
* 这里还是用classes做测试,多对多,也就是一个学生可以在多个班上课,一个班可以有多个学生
* @author arkulo
*
*/
public class Classes {
private int id;
private String className;
private Set<Student> student;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public Set<Student> getStudent() {
return student;
}
public void setStudent(Set<Student> student) {
this.student = student;
}
}
<?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="entity">
<class name="Classes" dynamic-update="true" lazy="false" >
<id name="id">
<generator class="native"/>
</id>
<property name="className" />
<set name="student" table="_relation_classes_student" lazy="false">
<!-- 这里维护一张中间表,student_id关联student表,classes_id关联classes表 -->
<key column="classes_id"></key>
<many-to-many class="Student" column="student_id"></many-to-many>
</set>
</class>
</hibernate-mapping>
实体类student.java
package entity;
import java.util.Set;
public class Student {
private int id;
private String name;
private Set classes;
public Set getClasses() {
return classes;
}
public void setClasses(Set classes) {
this.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;
}
}
<?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="entity">
<class name="Student" dynamic-update="true">
<id name="id">
<generator class="native"/>
</id>
<property name="name" />
<set name="classes">
<key column="student_id"></key>
<many-to-many class="Classes" column="classes_id"></many-to-many>
</set>
</class>
</hibernate-mapping>
单元测试:
package entity;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.hibernate.classic.Session;
import junit.framework.TestCase;
import util.hibernateUtil;
/**
* 测试目的:
* 这里测试的是关联实体多对多的情况,就是查看是否能够lazy加载
*
* 结果:
* 不同的标签(class,set)设置lazy为false,会对实体类,或者实体类相关的实体或实体集合产生影响
* @author arkulo
*
*/
public class testLazy extends TestCase {
// 数据准备
public void test1() {
Session session = null;
try {
session = hibernateUtil.getSession();
session.beginTransaction();
// 先插入3条学生记录,然后插入班级记录,又插入三条关系表记录
Student st1 = new Student();
st1.setName("张三");
Student st2 = new Student();
st2.setName("李四");
Student st3 = new Student();
st3.setName("王五");
session.save(st1);
session.save(st2);
session.save(st3);
Classes cl = new Classes();
cl.setClassName("音乐班");
Classes cl1 = new Classes();
cl1.setClassName("美术班");
Classes cl2 = new Classes();
cl2.setClassName("跆拳道班");
// 上音乐班的学生
Set<Student> jihe = new HashSet();
jihe.add(st1);
jihe.add(st2);
cl.setStudent(jihe);
// 上美术班的同学
Set<Student> jihe1 = new HashSet();
jihe1.add(st2);
jihe1.add(st3);
cl1.setStudent(jihe1);
// 上跆拳道班的学生
Set<Student> jihe2 = new HashSet();
jihe2.add(st1);
jihe2.add(st3);
cl2.setStudent(jihe2);
session.save(cl);
session.save(cl1);
session.save(cl2);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally {
hibernateUtil.closeSession(session);
}
}
// 这里是查询操作
public void test2()
{
test1();
System.out.println("------------------------------");
Session session = null;
try {
session = hibernateUtil.getSession();
session.beginTransaction();
// 当前实体类是Classes,class标签上使用lazy的默认设置(true),这里load使用了延时加载
// 如果set集合设置lazy为false,class的lazy为true,执行到load函数,当前实体Classes延迟,但是下句打印班级名称时,
// 是将classes和student一起查出来,共发出两个sql语句
Classes cl = (Classes)session.load(Classes.class, 1);
System.out.println("班级名称:"+cl.getClassName());
// set集合lazy设置为true,这是关联多个实体类,在下面从cl中获取student是没有发出sql语句的
// set集合lazy设置为false,在上面输出班级名称时,就一起发出sql查询了,没有执行延迟操作
Set<Student> sts = cl.getStudent();
// 在下面的iterator操作中发出了sql语句,延迟加载
for(Iterator<Student> it = sts.iterator();it.hasNext();)
{
Student student = it.next();
System.out.println("学生姓名:"+student.getName());
}
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally {
hibernateUtil.closeSession(session);
}
}
}
一对一测试
实体类User.java
package entity;
import java.util.Date;
public class User {
private int id;
private String userName;
private String passWd;
private Date addtime;
private Group group;
public Date getAddtime() {
return addtime;
}
public void setAddtime(Date addtime) {
this.addtime = addtime;
}
public User(){}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassWd() {
return passWd;
}
public void setPassWd(String passWd) {
this.passWd = passWd;
}
public Group getGroup() {
return group;
}
public void setGroup(Group group) {
this.group = group;
}
}
<?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="entity.User" lazy="false">
<id name="id">
<!-- 如果是uuid的话,需要id配置为String类型 -->
<!-- <generator class="uuid"/>-->
<generator class="identity" />
</id>
<property name="userName" />
<property name="passWd" />
<property name="addtime" type="time" />
<many-to-one name="group" column="group_id" class="entity.Group" lazy="proxy" />
</class>
</hibernate-mapping>
实体类Group.java
package entity;
public class Group {
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;
}
}
<?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="entity.Group" table="_group">
<id name="id">
<generator class="identity" />
</id>
<property name="name" />
</class>
</hibernate-mapping>
单元测试:
package entity;
import java.util.Date;
import org.hibernate.SessionFactory;
import org.hibernate.classic.Session;
import junit.framework.TestCase;
import util.hibernateUtil;
/**
* 测试目的:
* 这里是测试实体类关联另外一个实体类(一对一,多对一)的情况下,设置lazy
* 其实就是在many-to-one/one-to-one标签上设置lazy属性,然后查看延迟效果
*
* 这里设定的主实体类是user,也就是在user对应一个group
* @author arkulo
*
*/
public class UserTest extends TestCase {
/**
* 初始化数据写入,测试普通级联写入数据,和数据读取
*/
public void test1(){
Session session = null;
try {
session = hibernateUtil.getSession();
session.beginTransaction();
Group gp1 = new Group();
gp1.setName("产品组");
session.save(gp1);
User user1 = new User();
user1.setUserName("王蕊");
user1.setPassWd("123456");
user1.setGroup(gp1);
user1.setAddtime(new Date());
session.save(user1);
System.out.println("--------------------------------");
// 在一个session中,下面的代码会直接利用一级缓存
User userTmp = (User)session.load(User.class, 1);
System.out.println("用户名:"+userTmp.getUserName());
System.out.println("组名:"+userTmp.getGroup().getName());
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
hibernateUtil.closeSession(session);
}
}
// 读取数据,查看延迟加载情况
public void test2(){
test1();
System.out.println("--------------------------------");
Session session = null;
try {
session = hibernateUtil.getSession();
session.beginTransaction();
// class上的lazy设置不用说明,true就延迟,false就立刻
User userTmp = (User)session.load(User.class, 1);
System.out.println("用户名:"+userTmp.getUserName());
// many-to-one标签上lazy为true,延迟加载,如果为false,会在上面load函数的时候多发出一条查询group的sql
Group g = userTmp.getGroup();
System.out.println("组名:"+g.getName());
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
hibernateUtil.closeSession(session);
}
}
}