OpenSessionInViewInview是什么?
OpenSessionInViewFilter是Spring提供的一个针对Hibernate的一个支持类,其主要意思是在发起一个页面请求时打开Hibernate的Session,一直保持这个Session,直到这个请求结束,具体是通过一个Filter来实现的。
当然,在我的理解,OpenSessionInView是Hibernate的一种模式,因为官方也给出了相关代码。
JBoss的OpenSessionInView的地址:https://community.jboss.org/wiki/OpenSessionInView
OpenSessionInView简单来说,就是在请求到达View时Session不关闭,可以方便的调用Session中的方法。由于Hibernate引入了Lazy特性,使得脱离Hibernate的Session周期的对象如果再想通过getter方法取到其关联对象的值,Hibernate会抛出一个LazyLoad的Exception。所以为了解决这个问题,Spring和Hibernate都给出了相应的解决方案。
Spring的方案是一个过滤器,只需要你配置就OK了。
但是,我目前公司的项目用的是单Hibernate一个框架,以前公司未解决懒加载问题,将所有的关联对象的lazy全部设为false,这样大大降低了系统的运行效率,为了解决这个问题,自动翻阅资料,找到了Hibernate官方的OpenSessionInView模式。此模式是一个Filter。
package com.iit.common.hibernate3;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.SessionFactory;import org.hibernate.StaleObjectStateException;/* * Hibernate的OpenSessionInView过滤器,可以实现在页面中Session依旧不关闭,解决懒加载带来的副作用,可以随意使用懒加载,提升系统效率 * * @author wurt * */public class HibernateSessionRequestFilter implements Filter { private SessionFactory sf; public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { try { //开启Session和Transcation,在Hibernate查询中需要用getCurrentSession获取当前Session sf.getCurrentSession().beginTransaction(); // 放行 chain.doFilter(request, response); // Session提交,getCurrentSession获取的Session会在提交之后自动关闭 sf.getCurrentSession().getTransaction().commit(); } catch (StaleObjectStateException staleEx) { throw staleEx; } catch (Throwable ex) { // Rollback only ex.printStackTrace(); try { //如果Transcation依旧存在,回滚 if (sf.getCurrentSession().getTransaction().isActive()) { sf.getCurrentSession().getTransaction().rollback(); } } catch (Throwable rbEx) { rbEx.printStackTrace(); } // Let others handle it... maybe another interceptor for exceptions? throw new ServletException(ex); } } public void init(FilterConfig filterConfig) throws ServletException { // sessionFactory, 可以通过自己的代码获取此值 sf = HibernateSimpleDao.sessionFactory; } public void destroy() {} }
将此过滤器配置到web.xml,一切问题都解决了。
配制方法如下:
HibernateSessionInView com.iit.common.hibernate3.HibernateSessionRequestFilter HibernateSessionInView /*
然后将公司中Hibernate配置文件的lazy全部去掉,一切OK。
之前lazy="fasle"的情况下,载入Hibernate需要查询200+甚至更多的SQL,然而采用OpenSessionInView,仅仅需要99条(门户网站首页)。
为什么会有这么大的提升?
1.之前的SQL是不管用不用,只要是false,全部查出来再说;
2.现在的lazy都是true,在初次查询时,只会查询实体需要的字段,而不会查询关联的对象。当在View中需要关联时,才会去查询数据库。
lazy=true + OpenSessionInView可以避免很多不是必要的查询,速度自然会有所提升。
使用注意事项:
1.在Dao中无需再创建Transcation,因为过滤器已经创建好。
2.使用Session,请使用getCurrentSession来获取,得到当前的Session,而不是openSession,新建一个Session。
3.通过getCurrentSession获得的Session无需关闭,因为在过滤器提交时会自动关闭。
示例代码,仅仅贴出一个方法。
1 public ListgetAll(Class T) { 2 Session session = getCurrentSession(); 3 List list = null; 4 try{ 5 list = session.createQuery("from " + T.getName()).list(); 6 return list; 7 }catch (RuntimeException e){ 8 throw e; 9 } 10 }