在Java Web应用中,通常需要调用Hibernate API获取到要显示的某个对象并传给相应的视图JSP,并在JSP中从这个对象导航到与之关联的对象或集合数据。这些关联对象或集合数据如果是被延迟加载的,Hibernate就会抛出LazylnitializationException。因为在调用完FIibernate后,Session对象已经关闭了。针对这个问题,Hibernate社区提出了OpenSessionlnView模式作为解决方案。这个模式的主要思想是:在用户的每一次请求过程中始终保持一个Session对象打开。
OpenSessionlnView模式的具体实现有以下三个步骤:
第一步:把Session绑定到当前线程上,要保证在一次请求中只有一个Session对象。先在DAO包中创建HibernateUtil类。在程序代码中获取Session对象时,使用HibernateUtil.currentSession()方法。这样,可以保证每一次请求的处理线程上只有一个Session对象存在;关闭Session对象时,使用HibernateUtil.closeSession()方法。
第二步:用Filter过滤器在请求到达之前打开Session,在响应返回前关闭Session,完整案例如下所示。
============================index.jsp===========================
<body>
<h1><a href="LoadDemo.do?stuId=115">加载范冰冰的数据</a></h1>
</body>
=======================StudentDaoImpl.java======================
package com.obtk.dao;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import com.obtk.entitys.StudentEntity;
import com.obtk.utils.HiberUtil;
public class StudentDaoImpl implements StudentDao {
public StudentEntity getStuById(Integer stuId) {
StudentEntity stu=null;
Session session=null;
try {
session=HiberUtil.getSession();
System.out.println("dao:"+session.hashCode());
//延迟加载的报错
stu=(StudentEntity)session.load(StudentEntity.class, stuId);
} catch (HibernateException e) {
e.printStackTrace();
}
return stu;
}
}
package com.obtk.servlets;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.obtk.dao.StudentDao;
import com.obtk.dao.StudentDaoImpl;
import com.obtk.entitys.StudentEntity;
public class LoadDemoServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request,response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String stuIdStr=request.getParameter("stuId");
Integer stuId=Integer.parseInt(stuIdStr);
StudentDao stuDao=new StudentDaoImpl();
try {
StudentEntity stu=stuDao.getStuById(stuId);
request.setAttribute("theStu", stu.getStuId()+stu.getStuName());
} catch (Exception e) {
e.printStackTrace();
}
request.getRequestDispatcher("/ShowInfo.jsp").forward(request, response);
}
}
=======================OpenSessionInViewFilter.java==========================
package com.obtk.filters;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import com.obtk.utils.HiberUtil;
public class OpenSessionInViewFilter implements Filter {
public void doFilter(ServletRequest arg0, ServletResponse arg1,
FilterChain arg2) throws IOException, ServletException {
Session session=null;
try {
session=HiberUtil.getSession();
//和dao层获得的session是一个session
System.out.println("filter:"+session.hashCode());
System.out.println("请求开始了...");
arg2.doFilter(arg0, arg1); //执行请求
System.out.println("请求结束了");
} catch (HibernateException e) {
e.printStackTrace();
}finally{
HiberUtil.closeSession();//在请求结束了再关闭连接,解决延迟加载的问题
}
}
public void destroy() {
}
public void init(FilterConfig arg0) throws ServletException {
}
}
=======================ShowResult.jsp======================
<body>
<h2>查看数据:${requestScope.theStu }</h2>
</body>
=======================web.xml=======================
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<filter>
<filter-name>OpenSessionInView</filter-name>
<filter-class>com.obtk.filters.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>OpenSessionInView</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<description>test</description>
<display-name>test</display-name>
<servlet-name>LoadDemoServlet</servlet-name>
<servlet-class>com.obtk.servlets.LoadDemoServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoadDemoServlet</servlet-name>
<url-pattern>/LoadDemo.do</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
由OpenSessionInViewFilter这个过滤器就能完美的解决延迟加载带来的问题。