# 新人浅谈对hibernate的懒加载的理解
新人浅谈对hibernate的懒加载的理解
懒加载是hibernate中常见的特性之一。
懒加载的好处:
可以减少程序本身因为与数据库频繁交互数据所导致的处理速度缓慢。
对懒加载异常的分析:
实验代码如下:
Department类:
public class Department {
private Long id;
private Department parent;//关联上级部门
private Set<Department> children = new HashSet<Department>();//关联下级部门
private String name;
private String description;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Department getParent() {
return parent;
}
public void setParent(Department parent) {
this.parent = parent;
}
public Set<Department> getChildren() {
return children;
}
public void setChildren(Set<Department> children) {
this.children = children;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
Department.hbm.xml:
<!-- parent属性,本类与Department(上级)的多对一 -->
<many-to-one name="parent" class="Department" column="parentId"></many-to-one>
<!-- children属性,本类与Department(下级)的一对多 -->
<set name="children" cascade="delete" order-by="id ASC">
<key column="parentId"></key>
<one-to-many class="Department" />
</set>
DAO层代码:
public List<Department> findTopList() {
return sessionFactory.getCurrentSession().createQuery(
"FROM Department d WHERE d.parent IS NULL")
.list();
}
public List<Department> findChildren(Long parentId) {
return sessionFactory.getCurrentSession().createQuery(
"FROM Department d WHERE d.parent.id=?")
.setParameter(0, parentId)
.list();
}
Action:
public String list() throws Exception {
List<Department> departmentList = null;
if (parentId == null) { // *部门列表
departmentList = departmentService.findTopList();
} else { // 子部门列表
departmentList = departmentService.findChildren(parentId);
Department parent = departmentService.getById(parentId);
ActionContext.getContext().put("parent", parent);
}
ActionContext.getContext().put("departmentList", departmentList);
return "list";
}
执行该段代码,在第一次查询*部门时,是可以执行的,但是第二次查询子部门时,会出现懒加载异常。
原因分析:
执行findTopList()和findChildren方法时,默认使用懒加载,*即加载关联实体类时,并不是直接加载指定对象,而是加载一个代理对象,当你想使用关联实体类时在从数据库中查询。
*在视图层需要显示上级部门这个属性,这意味着要在视图层加载Department类 的parent 属性的name属性。
findTopList() 这个方法所查询的Department类 的parent是为null,故而不出现懒加载异常。
findChildren方法所查询出的parent不为null,当视图层加载parent的name属性是session已经被关闭了,此时懒加载之前加载的代理对象失效,无法从数据库中查询出parent的值,导致了懒加载异常的发生。
故而懒加载异常发生的主要原因是:实体类对象还未加载完成,负责加载实体类对象的session就已经关闭了。
解决方案:
①,设置lazy=”false”。该方法存在缺点,即减低了效率。我们将所有相关联的数据都查询了,频繁的查询降低了效率。不建议采用!
②,使用Spring的过滤器:OpenSessionInViewFilter;它把session绑定到请求线程中,session将自动的被Spring的事务管理器管理。即service层完成了事务,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>
PS:为了方便拦截器的使用,减低没必要使用,建议将Struts2的后缀统一,如*.action。
新人写博文,请多指教。