Hibernate延迟加载和即时加载

来源:互联网 发布:php授权验证系统2.6.8 编辑:程序博客网 时间:2024/05/21 17:36

1、基本概念

即时加载,就是立即去数据库查找,延迟加载,查询是不会立即访问数据库,而是返回代理对象,只有真正需要使用对象的时候才会访问数据库

一般来说,延迟加载要比即时加载节省资源,但是如果处理不当,延迟加载容易抛出异常。
举例:
在一个一对多例子中,班级和学生,班级类里面有学生类的引用并且班级的.hbm.xml中的lazy设置了true,

public class Grade implements Serializable {    private int gid;    private String gname;    private String gdesc;    //在一方定义一个多方的集合    private Set<Student> students=new HashSet<Student>();    public int getGid() {        return gid;    }    public void setGid(int gid) {        this.gid = gid;    }    public String getGname() {        return gname;    }    public void setGname(String gname) {        this.gname = gname;    }    public String getGdesc() {        return gdesc;    }    public void setGdesc(String gdesc) {        this.gdesc = gdesc;    }    public Set<Student> getStudents() {        return students;    }    public void setStudents(Set<Student> students) {        this.students = students;    }    public Grade(String gname, String gdesc) {        super();        this.gname = gname;        this.gdesc = gdesc;    }    public Grade() {        // TODO Auto-generated constructor stub    }

Teacher.hbm.xml

 <set name="students" table="student" cascade="save-update" inverse="false" lazy="true">   <key column="gid"></key>   <one-to-many class="entity.Student"/> </set>

测试

Session session=HibernateSessionFactoryUtil.getSession();Transaction tx=session.beginTransaction();Grade g=(Grade)session.get(Grade.class, 1);tx.commit();HibernateSessionFactoryUtil.closeSession(session);

控制台输出:
Hibernate: select grade0_.gid as gid0_0_, grade0_.gname as gname0_0_, grade0_.gdesc as gdesc0_0_ from grade grade0_ where grade0_.gid=?
只是打印了select班级的语句

当我们的测试添加 一句输出学生的姓名时
控制台输出(为了便于观察,我认为在第一个和第二个select语句中加了空行):

Hibernate: select grade0_.gid as gid0_0_, grade0_.gname as gname0_0_, grade0_.gdesc as gdesc0_0_ from grade grade0_ where grade0_.gid=?Hibernate: select students0_.gid as gid0_1_, students0_.sid as sid1_, students0_.sid as sid1_0_, students0_.sname as sname1_0_, students0_.sex as sex1_0_, students0_.gid as gid1_0_ from student students0_ where students0_.gid=?李四张三

张三李四是班级号为1的学生,只有在要使用grade对象的时候才会执行查询student的语句

如果此时还是没有看出异样,我们把Grade.hbm.xml的lazy设为false试一次

<set name="students" table="student" cascade="save-update" inverse="false" lazy="false">   <key column="gid"></key>    <one-to-many class="entity.Student"/></set>

测试:

session=HibernateSessionFactoryUtil.getSession();Transaction tx=session.beginTransaction();Grade g=(Grade)session.get(Grade.class, 1);tx.commit();HibernateSessionFactoryUtil.closeSession(session);

控制台输出(为了便于观察,我认为在第一个和第二个select语句中加了空行):

Hibernate: select grade0_.gid as gid0_0_, grade0_.gname as gname0_0_, grade0_.gdesc as gdesc0_0_ from grade grade0_ where grade0_.gid=?Hibernate: select students0_.gid as gid0_1_, students0_.sid as sid1_, students0_.sid as sid1_0_, students0_.sname as sname1_0_, students0_.sex as sex1_0_, students0_.gid as gid1_0_ from student students0_ where students0_.gid=?

发现了吧,在lazy=false时,也就是即时加载,就算不用Grade,他也会查找自己的外键(因为我们在set标签里设了lazy属性,所以加载外键,不懂的可以看我另一篇博客hibernate映射

2、出现的情景

(1)在.hbm.xml中可以设置加载方式,class标签中可以设置
(2)在set/bag标签下也可以设置
(3)映射(many-to-one、many-to-many、one-to-many)
(4)get支持即时加载,load支持懒加载

详细解释下get和load(来自:http://www.cnblogs.com/fingerboy/p/5256087.html)
一、
get和load方法都是根据id去获得对应数据的,但是获得机制不同:如果使用get方法,hibernate会去确认该id对应的数据是否存在,它首先会去session中去查询(session缓存其实就hibernate的一级缓存),如果没有,再去二级缓存中去查询,如果再没有,就去数据库中查询,仍然没有找到的话,就返回null
  而使用load方法的话,hibernate会认定该id对应的数据一定存在,它也会先去session缓存中去查找,如果没有找到,hibernate会根据lazy属性值来确定是否使用延迟加载。如果lazy=‘true’ ,就使用延迟加载,返回该代理对象,等到真正访问到该对象的属性时才会去二级缓存中查询,如果没有,再去数据库中查询,如果还没有,就抛出org.hibernate.ObjectNotFoundException异常。如果lazy=’false’ 则不使用延迟加载,这是load的访问机制就和get一样了。
二、
对于load和get方法返回类型:虽然好多书中都这么说:“get()永远只返回实体类”,但实际上这是不正确的,get方法如果在 session缓存中找到了该id对应的对象,如果刚好该对象前面是被代理过的,如被load方法使用过,或者被其他关联对象延迟加载过,那么返回的还是 原先的代理对象,而不是实体类对象,如果该代理对象还没有加载实体数据(就是id以外的其他属性数据),那么它会查询二级缓存或者数据库来加载数据,但是 返回的还是代理对象,只不过已经加载了实体数据。

0 0