单Hibernate实现OpenSessionInView

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,一切问题都解决了。

配制方法如下:

<filter>
    <filter-name>HibernateSessionInView</filter-name>
    <filter-class>com.iit.common.hibernate3.HibernateSessionRequestFilter</filter-class>
</filter> <filter-mapping> <filter-name>HibernateSessionInView</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>

然后将公司中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 List<T> getAll(Class T) {
 2     Session session = getCurrentSession();
 3     List<T> list = null;
 4     try{
 5         list = session.createQuery("from " + T.getName()).list();
 6         return list;
 7     }catch (RuntimeException e){
 8         throw e;
 9     } 
10 }
posted @ 2012-09-28 12:59  香蕉煎牛腩  阅读(634)  评论(0编辑  收藏  举报