由于Hibernate存在延迟加载的问题,当Dao的事物提交之后,session就关闭此时如果到显示层就没有办法获取对象,使用OpenSessionInViewer是解决延迟加载问题的方案。
解决的思路:
1.在表示层开启session
需要早表示层获取Spring的工厂,以此获取hibernate的SessionFactory
2.在Dao层获取表示层的session
如果希望在Dao层获取表示层的数据,一个将要获取的数据存储到ThreadLocal
3.当整个过程执行完闭之后再关闭session
需要通过filter来解决问题
1.创建一个filter
//以下方法用来获取Spring的工厂和hibernate的SessionFactory
@Override public void init(FilterConfig config) throws ServletException { /** * 使用WebApplicationContextUtils.getWebApplicationContext()来获取Spring的工厂 * 这种手段非常重要,一定要熟悉 */ wac = WebApplicationContextUtils.getWebApplicationContext(config .getServletContext()); factory = (SessionFactory) wac.getBean("sessionFactory"); }
private static ThreadLocal<Session> sessionHolder=new ThreadLocal<Session>(); private static void setSession(Session session){ sessionHolder.set(session); } public static Session getSession(){ return sessionHolder.get(); } private static void removeSession(){ sessionHolder.remove(); }
<!-- 如果把这个filter放在struts2的filter之后,所有的请求都会被struts2给控制,所以这个filter就不起作用了, 必须将这个filter放在struts2的filter之前--> <filter> <filter-name>OpenSessionInViewFilter</filter-name> <filter-class>org.oms.spring.filter.OpenSessionFilter</filter-class> </filter> <filter-mapping> <filter-name>OpenSessionInViewFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
OpenSessionFilter过滤器具体代码:
package org.oms.spring.filter; 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.Session; import org.hibernate.SessionFactory; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; public class OpenSessionFilter implements Filter { // Spring的工厂,在init中获取 private static WebApplicationContext wac; private static SessionFactory factory; private static ThreadLocal<Session> sessionHolder=new ThreadLocal<Session>(); private static void setSession(Session session){ sessionHolder.set(session); } public static Session getSession(){ return sessionHolder.get(); } private static void removeSession(){ sessionHolder.remove(); } @Override public void destroy() { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("begin"); // 开启session /** * 需要获取Spring工厂 如果使用new * ClassPathXmlApplicationContext()这种方式来获取Spring的工厂, * 和Spring在web.xml中得不兼容。 必须通过其他方法来获取 在Spring中可以通过Web */ try { //设置session setSession(factory.openSession()); chain.doFilter(request, response); }finally{ System.out.println("back"); // 关闭session removeSession(); } } @Override public void init(FilterConfig config) throws ServletException { /** * 使用WebApplicationContextUtils.getWebApplicationContext()来获取Spring的工厂 * 这种手段非常重要,一定要熟悉 */ wac = WebApplicationContextUtils.getWebApplicationContext(config .getServletContext()); factory = (SessionFactory) wac.getBean("sessionFactory"); } }
@Override public T load(int id) { //如果使用了自定义的OpenSessionFilter,需要按照如下方法来获取 // return (T)OpenSessionFilter.getSession().load(getClz(), id); /** * 如果使用了Spring提供的OpenSessionInViewFilter就按照整合的方法处理即可 */ return this.getHibernateTemplate().load(getClz(), id); }
这样就有效的解决了我们的延迟加载的问题!
当然在Spring中提供了OpenSessionInViewFilter的过滤器,以此我们只需要在web.xml中配置OpenSessionInViewFilter的过滤器,在load方法中继续使用HibernateTemplate的load方法!
个人备忘笔记~~~呵呵~~!