懒加载是指程序推迟访问数据库,这样作能够保证有时候没必要要的访问数据库,由于访问一次数据库是比较耗时的。
html
1、load方法的懒加载java
先看以下代码段linux
[java] view plaincopyprint?web
<EMBED id=ZeroClipboardMovie_1 name=ZeroClipboardMovie_1 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer height=14 width=29 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=1&width=29&height=14" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">数据库
<span style="font-size:16px;">public class UserManager { session
public static void main(String[] args) { app
Users user = new Users(); dom
user.setBirthday(new Date()); oop
Name name = new Name(); fetch
name.setFirstName("guo");
name.setLastName("zhao");
user.setName(name);
addUser(user);
Users users = getUser(user.getId());
System.out.println(users.getName());
}
static Users getUser(int id){
Session session = HibernateUtil.getSession();
try {
Users users = (Users) session.load(Users.class, id);
return users;
} finally{
session.close();
}
}
static void addUser(Users users){
Session session = null;
Transaction tx = null;
try {
session = HibernateUtil.getSession();
tx = session.beginTransaction();
session.save(users);
tx.commit();
} catch (HibernateException e) {
if (tx!=null) {
tx.rollback();
}
throw e;
}finally{
if(session!=null){
session.close();
}
}
}
}</span>
上面代码是先增长一个用户、而后再查询这个用户的name组合属性。运行上面的时候,该程序会抛出这样一个异常:
Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - no Session这就是懒加载不能初始化异常。其缘由就在于no session。在前面个持久化对象中已经说明:使用load方法时,该方法将具备延迟加载的功能,load方法并不会当即去访问数据库,它会返回一个代理对象,只有当你真正去访问这个对象的时候,它才会去访问数据库。
经过上面的图,咱们看出,hibernate根本就没有select语句,也就是说hibernate没有去访问数据库,因此这个时候你去访问它确定是没有的。但为何没有抛出空指针异常?没有抛出空指针异常,也就是说明User对象是存在的,那它是什么呢?经过输出user.getClass()能够看出是这样一个东西:
class com.hibernate.domain.Users_$$_javassist_5。
这个user就是load返回的代理对象。可是这个对象并非咱们所要的。咱们所要的是一个User实例对象。
那么怎么解决这个问题呢?
第一种方法:在关闭session以前访问该对象
[java] view plaincopyprint?
<EMBED id=ZeroClipboardMovie_2 name=ZeroClipboardMovie_2 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer height=14 width=29 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=2&width=29&height=14" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">
<span style="font-size:16px;"> static Users getUser(int id){
Session session = HibernateUtil.getSession();
try {
Users users = (Users) session.load(Users.class, id);
users.getName();
return users;
} finally{
session.close();
}
}</span>
不过这句话看起来会很奇怪。咱们一般会采用以下的方式
[java] view plaincopyprint?
<EMBED id=ZeroClipboardMovie_3 name=ZeroClipboardMovie_3 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer height=14 width=29 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=3&width=29&height=14" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">
<span style="font-size:16px;"> static Users getUser(int id){
Session session = HibernateUtil.getSession();
try {
Users users = (Users) session.load(Users.class, id);
Hibernate.initialize(users);
return users;
} finally{
session.close();
}
}</span>
利用hibernate的initialize()方法将这个代理对象给初始化。
注:在使用代理对象的getId()方法和getClass()方法的时候,并不会抛出不能初始化异常,由于这两个属性并不用查询数据库。
2、在缺省的状况下,hibernate对于关联关系会采用懒加载的方式。也就是说1-一、1-N、N-一、N-N都存在懒加载的问题。
2.一、one-to-one懒加载
一对一的懒加载并不经常使用,由于懒加载的目的是为了减小与数据库的交互,从而提升执行效率,而在一对一关系中,主表中的每一条数据只对应从表的一条数据库,就算都查询也不会增长多少交互的成本,并且主表不能有contrained=true,因此主表是不能懒加载的。可是从表能够有。
实现此种懒加载必须在从对象这边同时知足三个条件:
1、lazy!=false(lazy的属性有三个选项分别为:no-proxy、false和proxy)
2、Constrained = true ;
3、fetch=select。
注:当fetch设置为join时,懒加载就会失效。由于fetch的做用是抓取方式,他有两个值分别问select和join,默认值为select。即在设为join时,他会直接将从表信息以join方式查询到而不是再次使用select查询,这样致使了懒加载的失效。
2.二、one-to-many懒加载
与one-to-one关联不一样,对one-to-many而言,主表的每一条属性都会对应从表的多条数据,这个时候懒加载就显得很是有效了。好比一个部门里面有多个员工,若是没有懒加载,每查询这个部门的时候都会查询出多个员工,这会大大增长与数据库交互的成本。因此Hbernate默认的是加入懒加载的。这就是查询集合属性的时候返回的是一个PersistentIndexed*类型对象的缘由。该对象其实就是一个代理对象。固然,能够在映射文件中经过将lazy属性设为假来禁用。
Hibernate默认对one-to-many就是使用的懒加载,但用户也能够取消懒加载操做:
一:设置lazy=”false”;
二:设置fetch=”join”.
实现此种懒加载必须在从对象这边同时知足两个个条件:
1、lazy!=false(lazy的属性有三个选项分别为:no-proxy、false和proxy)
2、fetch=select。
2.三、mang-to-one懒加载
此关联关系的懒加载和one-to-one的懒加载同样都是可要可不要的,由于对执行效率的提升都不是很是明显。虽然多对一与一对一关系方式相同,可是在Hibernate中多对一时,默认是进行懒加载的。另外有一点须要注意的是懒加载并不会区分集合属性里面是否有值,即便是没有值,他依然会使用懒加载。
实现此种懒加载必须在从对象这边同时知足两个个条件:
1、lazy!=false(lazy的属性有三个选项分别为:no-proxy、false和proxy)
2、fetch=select
2.四、many-to-many懒加载
此关联关系的懒加载和one-to-many的懒加载同样对程序的执行效率的提升都是很是明显的。
实现此种懒加载必须在从对象这边同时知足两个个条件:
1、lazy!=false(lazy的属性有三个选项分别为:no-proxy、false和proxy)
2、fetch=select
可以懒加载的对象都是被改过的代理对象,当相应的对象没有关闭时,访问这些懒加载对象的属性(getId和getClass除外)hibernate会初始化这些代理,或用hibernate.initalize(proxy)来初始化代理对象;当关闭session后在访问懒加载的对象就会出现异常