Hibernate 解决延迟加载问题

09/03/2010

Hibernate 在加载关联对象时有两种加载方式:
延迟装载——关联对象何时用何时装载 hibernate3.x 默认使用延迟装载
即时装载——装载对象时立即加载关联对象 hibernate2.x 默认使用即时装载
1.什么是延迟加载问题
首先我们来回顾之前我们封装的业务DAO

/**
 * 雇员实体 
 * 包括:雇员编号,雇员姓名,雇员所在部门(关联至部门表)
 * @author RoyAkon
 */
public class Employee implements java.io.Serializable {
	private Integer employeeId;
	private Department department;
	private String employeeName;
	//Geter and Seter....
}

/**
 * 业务DAO 继承自 BaseHibernateDAO
 * @author Administrator
 */
public class HrDAO extends BaseHibernateDAO {
	/**
	 * 根据雇员编号取得雇员信息
	 * @param employeeId
	 * @return
	 */
	public Employee getEmployeeById(Integer employeeId) {
		Employee employee = null;
		try {
			employee = (Employee)super.getSession().get(Employee.class, employeeId);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			super.closeSession();
		}
		return employee;
	}
}

当我们使用雇员数据时,会发生什么事情呢?

/**
 * 测试-输出关联对象内容
 * @author Administrator
 */
public class Tester {
	public static void main(String[] args) {
		HrDAO dao = new HrDAO();
		System.out.print(employee.getDepartment().getDepartmentName());
	}
}
Exception in thread "main" org.hibernate.LazyInitializationException: 
	could not initialize proxy - the owning Session was closed

大家会发现程序抛出上述的的运行期错误,因为延迟加载机制的存在导致了当要使用关联对象的内容时,Hibernate 去动态加载需要的内容,但是我们在DAO封装时已经将Session关闭了。无法动态加载导致异常。如果保持Session那不是会破坏封装吗?如何解决这个问题呢?
如何解决延迟加载的问题?
1.对象配置文件配置 lazy=”false”
在对象配置文件中 关联属性项中配置 lazy=”false” 项目表示了当前关联对象需要即时加载方式

<!-- Employee.hbm.xml 中对其关联属性 雇员所在部门配置 lazy="false" -->
<many-to-one lazy="false" name="department" class="cn.net.royakon.entity.Department" fetch="select">
	<column name="employee_department" not-null="true" />
</many-to-one>

2.DAO封装业务时编写代码要求加载关联对象

  • 当业务DAO取得单个对象时
  • /**
     * 业务DAO 继承自 BaseHibernateDAO
     * @author Administrator
     */
    public class HrDAO extends BaseHibernateDAO {
    	/**
    	 * 根据雇员编号取得雇员信息
    	 * @param employeeId
    	 * @return
    	 */
    	public Employee getEmployeeById(Integer employeeId) {
    		Employee employee = null;
    
    		try {
    			employee = (Employee)super.getSession().get(Employee.class, employeeId);
    			//Hibernate立即加载关联对象
    			Hibernate.initialize(employee.getDepartment());
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			super.closeSession();
    		}
    
    		return employee;
    	}
    }
  • 当业务DAO取得对象集合时
  • /**
     * 业务DAO 继承自 BaseHibernateDAO
     * @author Administrator
     */
    public class HrDAO extends BaseHibernateDAO {
    	/**
    	 * 获取雇员信息集合
    	 * @return
    	 */
    	public List<Employee> getEmployeeList() {
    		List<Employee> list = null;
    		try {
    			Criteria c = super.getSession().createCriteria(Employee.class);
    			//设置标准查询 setFetchMode 模式 立即加载集合内所有关联对象
    			c.setFetchMode("department", FetchMode.JOIN);
    			list = c.list();
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			super.closeSession();
    		}
    		return list;
    	}
    }