load方法的懒加载及原理分析

[size=medium]懒加载:[/size]

[color=red] load方法与get方法的区别:
1.读取时机不同(当lazy=true的时候)
load是采用延迟机制(load语句不读库,等使用非主键时才去读库),而get不采用延迟机制(get语句时马上读库);

2.搜索不到数据时的情况
当搜索的数据不存在的时候,load依然会返回一个对象,在你使用该对象的非主键数据时,会抛出异常;
当搜索的数据不存在的时候,get会返回一个null;

[/color]


通过asm和cglib两个包实现;Domain是非final的。

1 session.load懒加载。

2 one-to-one(元素)懒加载:
必须同时满足下面三个条件时才能实现懒加载(主表不能有constrained=true,所以主表没有懒加载)1)lazy!=false 2)constrainted=true 3)fetch=select

3 one-to-one(元素)懒加载:1)lazy!=false 2)fetch=select

4 many-to-many(元素):1)lazy!=false 2)fetch=select

5 many-to –many(元素):1)lazy!=false 2)fetch=select

6 懒加载的对象都是被改写过的代理对象,当相关联的session没有关闭时,访问这些懒加载对象(代理对象)的属性(getId和getClass除外)hibernate会初始化这些代理,或用Hibernate.initialize(proxy)来初始化代理对象;当相关联的session关闭后,再访问懒加载的对象将会出现异常。


******************************************************

1.lazy是什么
Hibernate中的lazy(默认true)网上很多人都把它叫懒人机制,主要是告诉Hibernate获取数据时在什么时候去读库;

2.lazy的影响
就我做的例子看来。lazy只对session.Load和获取级联信息(1对1,1对多,多对多)时起作用;

3.Session读取信息的方式(Load和级联信息)
3.1延迟加载(lazy=true)
当我用Load或者是该bean中有级联对象的时候,执行Load的时候并不去读库,但Load还是会返回一个对象给你,但该对象中只有主键,读库是在你使用该对象的其他属性的时候去读的;
3.2非延迟加载(lazy=false)
在执行Load的时候就会去把库中的数据读取出来;

4.出问题的地方
由于我们要保证Session要及时关闭,即Load完之后,我们要执行session.close操作;但是当lazy为真的时候,在Load的时候并是直接去读库,而是等使用里面属性的时候才去读库。那么到你打印信息的时候就会报session已经被关闭的错误。
现在你是否要问,那直接把lazy设置成false不就可以了吗?现在看下面的例子吧:

5.例子(要调用Hibernate的show_sql为真)
5.1lazy不设置,或者设置为true的时候(Load的情况)
5.1.1代码
 Session session = HibernateSessionFactory.getSession();//获取session
Tabuser tabuser = (Tabuser) session.load(Tabuser.class, new Long(1));//获取数据
HibernateSessionFactory.closeSession();//关闭session
System.out.println(tabuser.getUserid());
System.out.println(tabuser.getUsername());

5.1.2问题
这时会提示第5行代码出错the owning Session was closed;
这是由于session已经被你关闭了;
5.1.3解决
这时的解决办法有四种:
a)设置class标签的lazy=false;(这种方式不推荐使用)
b)在第三行之前加入Hibernate.initialize(tabuser);
c)使用get方法(推荐使用这个,《get和load的区别》)
d)使用spring(网上看到的:用filter[由于spring我还不懂,现在不讲这种方式,可能这种方式会更好])
5.2一对多映射中set标签下lazy不设置,或者设置为true的时候(获取级联信息的情况1对多)
5.2.1代码
 Session session = HibernateSessionFactory.getSession();
Tabuser tabuser = (Tabuser) session.get(Tabuser.class, new Long(1));
HibernateSessionFactory.closeSession();
System.out.println(tabuser.getUserid());
System.out.println(tabuser.getUsername());
System.out.println(tabuser.getPostlist().iterator().next().getPostid());
5.2.2问题
这时第6行会报错no session or session was closed;
这是由于session已经被你关闭了;
5.2.3解决方法有三种:
a)set标签下设置lazy=false;(这种方式不可行)
b)在第三行之前加入Hibernate.initialize(tabuser.getPostlist());
c)使用spring
5.2.4为什么说设置lazy=false不可行
由于你在set标签后设置lazy=false的时候,那么以后你再搜索数据的时候,Hibernate都会去获取其对应的set列表(那是否浪费掉非常多的资源,设置了这个值,可能会把整个数据库中与tabuser表有级联关系的数据全读出来[一条链子])
6.总结
大家可以运行上面的例子,并注意观察打印信息及HQL显示的位置,即可推断出HQL是什么时候执行的

7.补充
有涉及到延迟读取好像只有Load读取和级联信息
如果获取信息用Query的话,则执行query.list的时候就已经读库了

[color=darkred]代码一: 此时session没有关闭,所以正常访问[/color]
	public static void main(String[] args) {

Session session = HibernateUtil.getSession();
Transaction tx = session.beginTransaction();

User user = new User("username",12356f);
session.save(user);

User user2 = (User)session.load(User.class, 1);

System.out.println(user2.getId());
System.out.println(user2.getName());

tx.commit();
session.close();


}

[color=darkred]
代码二:此时session已经关闭,出现异常[/color]

	public static void main(String[] args) {

Session session = HibernateUtil.getSession();
Transaction tx = session.beginTransaction();

User user = new User("username",12356f);
session.save(user);

User user2 = (User)session.load(User.class, 1);

System.out.println(user2.getId());

tx.commit();
session.close();

System.out.println(user2.getName());
}


[color=darkred]代码三:利用Hibernate的initial方法初始化,session关闭后也访问正常[/color]

	public static void main(String[] args) {

Session session = HibernateUtil.getSession();
Transaction tx = session.beginTransaction();

User user = new User("username",12356f);
session.save(user);

User user2 = (User)session.load(User.class, 1);
Hibernate.initialize(user2);
System.out.println(user2.getId());

tx.commit();
session.close();

System.out.println(user2.getName());
}

[color=darkred]
代码四:测试代码如上,然后修改映射文件[/color]

<?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="cn.itcast.hibernate.lazy">

<class name="User" table="user" lazy="false">
<id name="id" unsaved-value="-1">
<generator class="native" />
</id>
<property name="name" />
<property name="wage"/>

</class>
</hibernate-mapping>


[color=red]注意:lazy="false">[/color]

此时访问及时session关闭,那也会正常
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值