`

OpenSessionInView详解

阅读更多

OpenSessionInViewFilter是Spring提供的一个针对Hibernate的一个支持类,其主要意思是在发起一个页面请求时打开Hibernate的Session,一直保持这个Session,直到这个请求结束,具体是通过一个Filter来实现的。

由于Hibernate引入了Lazy Load特性,使得脱离Hibernate的Session周期的对象如果再想通过getter方法取到其关联对象的值,Hibernate会抛出一个LazyLoad的Exception。所以为了解决这个问题,Spring引入了这个Filter,使得Hibernate的Session的生命周期变长。

首先分析一下它的源码,可以发现,它所实现的功能其实比较简单:

Java代码
SessionFactory sessionFactory = lookupSessionFactory(request);   
Session session = null;   
boolean participate = false;   
  
if (isSingleSession()) {   
    // single session mode   
    if (TransactionSynchronizationManager.hasResource(sessionFactory)) {   
    // Do not modify the Session: just set the participate flag.   
    participate = true;   
       }    else {   
    logger.debug("Opening single Hibernate Session in OpenSessionInViewFilter");   
    session = getSession(sessionFactory);   
    TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));   
    }   
} else {   
    // deferred close mode   
    if (SessionFactoryUtils.isDeferredCloseActive(sessionFactory)) {   
// Do not modify deferred close: just set the participate flag.   
    participate = true;   
    } else {   
    SessionFactoryUtils.initDeferredClose(sessionFactory);   
    }   
}   
  
try {   
    filterChain.doFilter(request, response);   
} finally {   
    if (!participate) {   
            if (isSingleSession()) {   
                // single session mode   
        TransactionSynchronizationManager.unbindResource(sessionFactory);   
        logger.debug("Closing single Hibernate Session in OpenSessionInViewFilter");   
        closeSession(session, sessionFactory);   
    }else {   
        // deferred close mode   
        SessionFactoryUtils.processDeferredClose(sessionFactory);   
    }   
}   
}  
SessionFactory sessionFactory = lookupSessionFactory(request);
Session session = null;
boolean participate = false;

if (isSingleSession()) {
 // single session mode
 if (TransactionSynchronizationManager.hasResource(sessionFactory)) {
 // Do not modify the Session: just set the participate flag.
 participate = true;
       } else {
 logger.debug("Opening single Hibernate Session in OpenSessionInViewFilter");
 session = getSession(sessionFactory);
 TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));
 }
} else {
 // deferred close mode
 if (SessionFactoryUtils.isDeferredCloseActive(sessionFactory)) {
// Do not modify deferred close: just set the participate flag.
 participate = true;
    } else {
 SessionFactoryUtils.initDeferredClose(sessionFactory);
    }
}

try {
 filterChain.doFilter(request, response);
} finally {
 if (!participate) {
            if (isSingleSession()) {
           // single session mode
  TransactionSynchronizationManager.unbindResource(sessionFactory);
  logger.debug("Closing single Hibernate Session in OpenSessionInViewFilter");
  closeSession(session, sessionFactory);
 }else {
  // deferred close mode
  SessionFactoryUtils.processDeferredClose(sessionFactory);
 }
}
}

在上述代码中,首先获得SessionFactory,然后通过SessionFactory获得一个Session。然后执行真正的Action代码,最后根据情况将Hibernate的Session进行关闭。整个思路比较清晰。

注意,在这里有个2个Tips:
1)通过getSession()获得的这个Session做了一次
session.setFlushMode(FlushMode.NEVER); 有关FlushMode可以参考一下这篇文章。http://www2.matrix.org.cn/resource/article/2006-10-08/Hibernate+FlushMode+NEVER_312bca85-5699-11db-91a0-d98dff0aec60.html
2)Spring对拿到的Session做了一次绑定到当前线程的做法,使得这个Session是线程安全的。

从上述代码其实可以得到一些对我们的开发有帮助的结论:
1)如果使用了OpenSessionInView模式,那么Spring会帮助你管理Session的开和关,从而你在你的DAO中通过HibernateDaoSupport拿到的getSession()方法,都是绑定到当前线程的线程安全的Session,即拿即用,最后会由Filter统一关闭。
2)由于拿到的Hibernate的Session被设置了session.setFlushMode(FlushMode.NEVER); 所以,除非你直接调用session.flush(),否则Hibernate session无论何时也不会flush任何的状态变化到数据库。因此,数据库事务的配置非常重要。(我们知道,在调用org.hibernate.Transaction.commit()的时候会触发session.flush())我曾经见过很多人在使用OpenSessionInView模式时,都因为没有正确配置事务,导致了底层会抛出有关FlushMode.NEVER的异常。

OpenSessionInView这个模式使用比较简单,也成为了大家在Web开发中经常使用的方法,不过它有时候会带来一些意想不到的问题,这也是在开发中需要注意的。
1. 在Struts+Spring+Hibernate环境中,由于配置的问题导致的模式失效
这个问题以前论坛曾经讨论过,可以参考一下下面这个帖子:
http://www.iteye.com/topic/15057

2. OpenSessionInView的效率问题
这个问题也有人在论坛提出过,Robbin曾经做过具体的测试,可以具体参考一下下面这个帖子:
http://www.iteye.com/topic/17501

3. 由于使用了OpenSessionInView模式后造成了内存和数据库连接问题
这个问题是我在生产环境中碰到的一个问题。由于使用了OpenSessionInView模式,Session的生命周期变得非常长。虽然解决了Lazy Load的问题,但是带来的问题就是Hibernate的一级缓存,也就是Session级别的缓存的生命周期会变得非常长,那么如果你在你的Service层做大批量的数据操作时,其实这些数据会在缓存中保留一份,这是非常耗费内存的。还有一个数据库连接的问题,存在的原因在于由于数据库的Connection是和Session绑在一起的,所以,Connection也会得不到及时的释放。因而当系统出现业务非常繁忙,而计算量又非常大的时候,往往数据连接池的连接数会不够。这个问题我至今非常头痛,因为有很多客户对数据连接池的数量会有限制,不会给你无限制的增加下去。

4. 使用了OpenSessionInView模式以后取数据的事务问题
在使用了OpenSessionInView以后,其实事务的生命周期比Session的生命周期来得短,就以为着,其实有相当一部分的查询是不被纳入到事务的范围内的,此时是否会读到脏数据?这个问题我至今不敢确认,有经验的朋友请指教一下。

最后提一下OpenSessionInView模式的一些替代方案,可以使用OpenSessionInViewInterceptor来代替这个Filter,此时可以使用Spring的AOP配置,将这个Interceptor配置到你所需要的层次上去。另外就是只能使用最古老的Hibernate.initialize()方法进行初始化了。

更详细请参考:http://www.iteye.com/topic/32001

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/yezi77321660/archive/2009/03/30/4036840.aspx

分享到:
评论

相关推荐

    Spring hibernate opensessioninview

    #### 一、OpenSessionInViewFilter详解 `OpenSessionInViewFilter`是Spring为配合Hibernate设计的一个过滤器,其主要作用是在Web请求处理过程中打开并维持一个Hibernate Session,直到视图渲染完成。这样做的好处...

    Open_Session_In_View详解.doc

    ### Open_Session_In_View详解 #### 一、背景与概念 在使用Hibernate进行对象持久化时,经常遇到的一个问题是关于懒加载(lazy loading)的处理。懒加载是一种优化技术,允许在真正需要某个关联对象的数据时才加载...

    SSH分页技术详解与实例

    2. **预加载**:使用OpenSessionInView模式,避免因多次打开和关闭Session导致的性能损失。 3. **懒加载**:对于关联对象,可采用懒加载策略,减少数据加载量。 4. **动态SQL**:使用MyBatis或JPA等框架,可以方便...

    SSH全注解环境搭建

    ### SSH全注解环境搭建详解 #### 一、概述 SSH框架是指Struts2、Spring、Hibernate这三种技术的组合,常被用于Java Web开发中。全注解配置相较于XML配置更加简洁,易于维护,因此在现代Web项目开发中越来越受到...

    详解SpringMVC拦截器配置及使用方法

    - OpenSessionInView:在Web层统一管理数据库会话的开启与关闭,避免数据库连接泄露。 2. 拦截器配置 在SpringMVC的配置文件中,可以配置多个拦截器。这些拦截器会按顺序执行。在配置文件中定义拦截器时,通常...

    spring+spingmvc+hibernate整合总结

    《Spring+SpringMVC+Hibernate整合详解》 在Java Web开发中,Spring、SpringMVC和Hibernate是三个非常重要的框架,它们分别负责依赖注入、Web请求处理和对象关系映射。将这三个框架整合在一起,可以构建出高效、...

    Spring配置总结

    #### 二、Spring配置详解 ##### 1. **web.xml中的Spring配置** - **载入Log4j配置**: 在web.xml中,我们可以通过`<context-param>`标签来载入Log4j配置。这是因为Spring应用通常需要日志记录功能,而Log4j是...

    Spring框架1

    【Spring框架1】知识点详解: 1. **Spring AOP(面向切面编程)**:Spring AOP 是一种用于实现横切关注点(如日志、事务管理)的技术,它允许我们在不修改源代码的情况下,向应用程序中添加额外的功能。Spring AOP ...

    hibernate 中的lazy属性祥解.txt

    ### `lazy`属性详解 `lazy`属性是Hibernate中用于控制数据加载策略的一个关键参数,主要用于延迟加载关联对象。当一个对象被加载时,与其关联的对象不一定立即加载到内存中,而是等到真正需要使用时才加载,这就是...

    SSH面试题

    ### SSH面试题详解 #### 一、Struts的Action线程安全性 **问题:** Struts的Action是否线程安全?如果不是,如何确保Action的线程安全? - **Struts 1**: 非线程安全。Struts 1中Action采用的是单例模式,即整个...

    ssh配置总结

    ### SSH配置总结与部署步骤详解 #### 一、SSH框架简介 SSH框架是Java Web开发领域内非常流行的一种组合框架,分别由Struts2、Spring和Hibernate三个技术组成。其中Struts2负责处理Web层逻辑;Spring则主要作为业务...

    java程序员ssh面试常见题

    ### Java程序员SSH面试常见题详解 #### 1. Action是什么?如何证明Action是线程安全的? - **知识点概述**:在Struts框架中,Action是处理用户请求的核心组件之一,它负责执行业务逻辑并返回相应的结果。由于...

    韩顺平spring 雇员管理系统hibernate jar包

    《韩顺平Spring雇员管理系统中的Hibernate ORM框架详解》 在现代软件开发中,数据库管理和对象关系映射(ORM)框架扮演着至关重要的角色。韩顺平老师的"Spring雇员管理系统"教学资源,重点关注了使用Hibernate ORM...

    SSH面试总结(非常全)

    #### Java面试宝典与SSH常问问题详解 在IT行业中,尤其是对于专注于Java开发的专业人士来说,掌握SSH框架(即Struts、Spring和Hibernate)的相关知识是至关重要的。这份“SSH面试总结”不仅涵盖了广泛的Java面试...

    struts spring hibernate面试题

    ### Struts、Spring、Hibernate 面试题详解 #### 1. Action 是否线程安全?如果不是,如何保证 Action 的线程安全? - **答案**:通常情况下,Struts 的 Action 不是线程安全的。因为同一个 Action 实例可能会被多...

    spring管理struts和hibernate

    ### Spring管理Struts与Hibernate详解 #### 一、Spring整合Struts 在Web开发中,Struts是一个基于MVC设计模式的开源框架,它能够帮助开发者构建可维护性高、结构清晰的应用系统。Spring框架则提供了强大的依赖注入...

    java ssh 面试题

    ### Java SSH面试题详解 #### 1. Action 是否线程安全? **背景介绍:** - **Struts1:** 在 Struts1 中,Action 对象是单例模式的,这意味着所有的请求都共享同一个 Action 实例。因此,在 Struts1 中 Action 是*...

    configuration

    ### 二、web.xml配置详解 `web.xml`是Java Web应用的核心配置文件,它定义了应用的初始化参数、监听器、过滤器、Servlet映射等信息。在给定的部分内容中,我们可以看到以下关键配置: #### 1. 应用基础信息 ```...

    java 并发编程 多线程

    ### Java并发编程与多线程知识点详解 #### 1. 线程安全与锁定机制 - **确保线程安全**: 在Java并发编程中,确保线程安全是至关重要的。通常有三种方法来实现这一点: - 使用`synchronized`关键字:这是最基本的...

Global site tag (gtag.js) - Google Analytics