懒加载:Hibernae 的延迟加载是一个非常常用的技术,实体的集合属性默认会被延迟加载,实体所关联的实体默认也会被延迟加载。Hibernate 通过这种延迟加载来降低系统的内存开销,从而保证 Hibernate 的运行性能。
当 Hibernate 从数据库中初始化某个持久化实体时,该实体的集合属性是否随持久化类一起初始化呢?如果集合属性里包含十万,甚至百万的记录,在初始化持久化实体的同时, 完成所有集合属性的抓取,将导致性能急剧下降。完全有可能系统只需要使用持久化类集合属性中的部分记录,而完全不是集合属性的全部,这样,没有必要一次加 载所有的集合属性。
load()方法的懒加载原理:
在Hibernate中,查询方法有两个,分别是get()和load(),这两种方法的不同就是load()拥有懒加载的特性。Load()方法就是在查询某一条数据的时候并不会直接将这条数据以指定对象的形式来返回,而是在你真正需要使用该对象里面的一些属性的时候才会去数据库访问并得到数据。他的好处就是可以减少程序本身因为与数据库频繁的交互造成的处理速度缓慢。
懒加载异常原因:
调用这个方法并返回查询到的代理对象,在返回关联对象后打印该对象的name属性,这时会抛出一个org.hibernate.LazyInitializationException异常。这就是懒加载不能初始化异常,这就说明了一件事,懒加载的时候如果想通过代理对象查询数据库,需要在该session关闭以前才可以。但如果一定要在session关闭以后再使用代理对象的话,Hibernate中定义了一个初始化代理对象的方法initialize(),通过该方法即可将代理对象初始化
举个例子
方法一:关闭lazy="false"懒加载:关闭延迟加载功能(不推荐使用)
1.JSP页面
<s:iterator value="#departmentList"> <tr class="TableDetail1 template"> <td width="20%">${name} </td> <td width="20%">${parent.name}</td> <td width="20%">${description} </td> <td width="40%"> <s:a action="departmentAction_delete?id=%{id}" onclick="return confirm('这将删除所有的下级部门,确认要删除么?')">删除</s:a> <s:a action="departmentAction_editUI?id=%{id}">修改</s:a> <a href="setPrivilegeUI.html">设置权限</a> </td> </tr> </s:iterator>
public class Department { /**主键*/ private Long id; /**一般属性*/ private String name; private String description; /**关联属性*/ private Department parent; private Set<Department> children = new HashSet<Department>(); //对应的Getter和Setter方法 }3.映射文件
<class name="Department" table="department"> <id name="id"> <generator class="native" /> </id> <property name="name" /> <property name="description" /> <!-- parent属性,本类与Department(上级)的多对一 --> <!-- 多对一,外键在"多"的一方 lazy="false" --> <many-to-one name="parent" class="Department" column="parentId"<span style="color:#ff6666;"> lazy="false"</span>/> <!-- children属性,本类与Department(下级)的一对多 order-by属性:指定的是sql的orderby子句内容 --> <!-- cascade="delete"对下级部门级联删除 --> <set name="children" cascade="delete" order-by="id ASC"<span style="color:#ff0000;"> lazy="false"</span>> <key column="parentId"></key> <one-to-many class="Department"/> </set> </class>
public List<Department> findAll() { // TODO Auto-generated method stub //SQL语句关键字不区分大小写,但是Role 是根据类名,区分大小写 //2.getSimpleName()得到类名,getName()得到包名+类名 return getSession().createQuery(// "FROM Department" .list(); }5. Hibernate配置文件中添加以下属性
<property name="hibernate.show_sql">true</property>
方法二:j交由过滤器控制,使session的生命周期延长,把Session关闭延长至页面加载数据完毕。
<!-- 配置Spring的用于解决懒加载问题的过滤器 --> <filter> <filter-name>OpenSessionInViewFilter</filter-name> <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class> </filter> <filter-mapping> <filter-name>OpenSessionInViewFilter</filter-name> <url-pattern>*.action</url-pattern> </filter-mapping>