`

open session in view 问题

阅读更多

     在没有使用Spring提供的Open Session In View情况下,因需要在service(or Dao)层里把session关闭,所以lazy loading 为true的话,要在应用层内把关系集合都初始化,如 company.getEmployees(),否则Hibernate抛session already closed Exception;    Open Session In View提供了一种简便的方法,较好地解决了lazy loading问题.    
    它有两种配置方式OpenSessionInViewInterceptor

OpenSessionInViewFilter(具体参看 SpringSide),功能相同,只是一个在web.xml配置,另一个在application.xml配置而已。    
     Open Session In View在request把session绑定到当前thread期间一直保持hibernate session在open状态,使session在request的整个期间都可以使用,如在View层里PO也可以lazy loading数据,如 ${ company.employees }。当View 层逻辑完成后,才会通过Filter的doFilter方法或Interceptor的postHandle方法自动关闭session。


     OpenSessionInViewInterceptor配置


<beans>   
<bean name="openSessionInViewInterceptor" class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">   
<property name="sessionFactory">   
<ref bean="sessionFactory"/>   
</property>   
</bean>   
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">   
<property name="interceptors">   
<list>   
<ref bean="openSessionInViewInterceptor"/>   
</list>   
</property>   
<property name="mappings">   
 ...   
</property>   
 </bean> ... </beans>

 


OpenSessionInViewFilter配置


<web-app>   
...   
<filter>   
<filter-name>hibernateFilter</filter-name>   
<filter-class> org.springframework.orm.hibernate3.support.OpenSessionInViewFilter </filter-class>   
<!-- singleSession默认为true,若设为false则等于没用OpenSessionInView -->   
<init-param>   
<param-name>singleSession</param-name>   
<param-value>true</param-value>   
</init-param>   
</filter> ... <filter-mapping>   
<filter-name>hibernateFilter</filter-name>   
<url-pattern>*.do</url-pattern>   
</filter-mapping> ... </web-app> 

    

     很多人在使用OpenSessionInView过程中提及一个错误:
org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.NEVER) - turn your Session into FlushMode.AUTO or remove 'readOnly' marker from transaction definition
    看看OpenSessionInViewFilter里的几个方法

protected void doFilterInternal(HttpServletRequest request,   
        HttpServletResponse response,  
        FilterChain filterChain) throws ServletException, IOException {   
        SessionFactory sessionFactory = lookupSessionFactory();   
        logger.debug("Opening Hibernate Session in OpenSessionInViewFilter");   
        Session session = getSession(sessionFactory);   
        TransactionSynchronizationManager.bindResource(    
                sessionFactory, new SessionHolder(session));   
        try {    
            filterChain.doFilter(request, response);   
            }   
        finally {   
            TransactionSynchronizationManager.unbindResource(sessionFactory);   
        logger.debug("Closing Hibernate Session in OpenSessionInViewFilter");   
        closeSession(session, sessionFactory);   
        }  
}   
protected Session getSession(SessionFactory sessionFactory)  
                   throws DataAccessResourceFailureException {   
        Session session = SessionFactoryUtils.getSession(sessionFactory, true);   
        session.setFlushMode(FlushMode.NEVER);   
        return session;  
}  
protected void closeSession(Session session,   
        SessionFactory sessionFactory)throws CleanupFailureDataAccessException {   
    SessionFactoryUtils.closeSessionIfNecessary(session, sessionFactory);  
}  

    

      在这个过程中,若HibernateTemplate 发现自当前session有不是readOnly的transaction,就会获取到FlushMode.AUTO Session,使方法拥有 权限。也即是,如果有不是readOnly的transaction就可以由Flush.NEVER转为 Flush.AUTO,拥有insert,update,delete操作权限,如果没有transaction,并且没有另外人为地设flush model的话,则doFilter的整个过程都是Flush.NEVER。所以受transaction保护的方法有写权限,没受保护的则没有。
     可能的解決方式有:
1、将singleSession设为false,这样只要改web.xml,缺点是Hibernate Session的Instance可能会大增,使用的JDBC Connection量也会大增,如果Connection Pool的maxPoolSize设得太小,很容易就出问题。
2、在控制器中自行管理Session的FlushMode,麻烦的是每个有Modify的Method都要多几行程式。     
session.setFlushMode(FlushMode.AUTO);      
session.update(user);      
session.flush();
3、Extend OpenSessionInViewFilter,Override protected Session getSession(SessionFactory sessionFactory),将FlushMode直接改为Auto。
4、让方法受Spring的事务控制。这就是常使用的方法: 采用spring的事务声明,使方法受transaction控制 


<bean id="baseTransaction" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"             
abstract="true">           
<property name="transactionManager" ref="transactionManager"/>           
<property name="proxyTargetClass" value="true"/>           
<property name="transactionAttributes">               
<props>                   
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>                   
<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>                   
<prop key="load*">PROPAGATION_REQUIRED,readOnly</prop>                   
<prop key="save*">PROPAGATION_REQUIRED</prop>                   
<prop key="add*">PROPAGATION_REQUIRED</prop>                   
<prop key="update*">PROPAGATION_REQUIRED</prop>                   
<prop key="remove*">PROPAGATION_REQUIRED</prop>               
</props>           
</property>       
</bean>       
<bean id="userService" parent="baseTransaction">           
<property name="target">               
<bean class="com.phopesoft.security.service.impl.UserServiceImpl"/>           
</property>       
</bean>   

     对于上例,则以save,add,update,remove开头的方法拥有可写的事务,如果当前有某个方法,如命名为importExcel(),则因没有transaction而没有写权限,这时若方法内有insert,update,delete操作的话,则需要手动设置flush model为Flush.AUTO,如 session.setFlushMode(FlushMode.AUTO); session.save(user); session.flush();      
    尽管Open Session In View看起来还不错,其实副作用不少。看回上面OpenSessionInViewFilter的doFilterInternal方法代码,这个方法实际上是被父类的doFilter调用的,因此,我们可以大约了解的OpenSessionInViewFilter调用流程: request(请求)->open session并开始transaction->controller->View(Jsp)->结束transaction并 close session.     
    一切看起来很正确,尤其是在本地开发测试的时候没出现问题,但试想下如果流程中的某一步被阻塞的话,那在这期间connection就一直被占用而不释放。最有可能被阻塞的就是在写Jsp这步,一方面可能是页面内容大,response.write的时间长,另一方面可能是网速慢,服务器与用户间传输时间久。当大量这样的情况出现时,就有连接池连接不足,造成页面假死现象。 Open Session In View是个双刃剑,放在公网上内容多流量大的网站请慎用。   另外:这样会产生一点危险性,毕竟把数据库访问的环境放到了表现层。(:用VO)      


具体可参考:

http://www.iteye.com/topic/186068

http://www.iteye.com/topic/32001

 

分享到:
评论

相关推荐

    Open Session in View模式.PPT

    Open Session in View (OSIV) 模式是一种在基于Hibernate的Web应用程序中处理持久化数据的策略,它允许在视图层(例如JSP页面)中安全地访问延迟加载的对象,而无需担心Session已关闭的问题。以下是关于这个模式及其...

    struts2+hibernate3 open session in view

    在这个小项目中,"Open Session in View"(OSIV)模式被采用,这是一种处理持久化数据的策略,以避免在Web应用中出现常见的并发问题,如数据不一致和懒加载异常。 Struts2是一个强大的MVC框架,它提供了一种灵活的...

    Open_Session_In_View详解.doc

    为了解决这一问题,Spring框架提供了`Open Session In View`机制,这是一种简便而有效的解决方案。它能够在Web请求的整个生命周期内保持`Hibernate session`处于打开状态,从而支持懒加载数据的获取,无需在应用层...

    使用Spring引起的错误

    这个问题通常发生在使用Spring提供的Open Session In View模式时。 #### Open Session In View 概念 Open Session In View是一种在Spring框架中常用的技术,用于简化Hibernate中的懒加载(lazy loading)机制。通过...

    Hibernate Session释放模式

    3. **Open Session in View(OSIV)模式** OSIV模式旨在解决Web应用中,由于用户请求可能会引发多次数据库操作,而这些操作可能跨多个HTTP请求。在这种模式下,Session在整个HTTP请求周期内保持打开状态,直到请求...

    hibernate中session的管理

    3. **Open Session in View (OSIV)**:在视图渲染阶段保持Session打开,以允许最后时刻的懒加载,但需要注意防止Session泄露。 总的来说,Hibernate中Session的管理是保证多线程环境下数据一致性的重要环节。...

    spring中lazy=“true”的正常读取关联表(用opensessioninview)

    为了解决这个问题,Spring提供了一个过滤器 `OpenSessionInViewFilter` 或者 `OpenSessionInViewInterceptor`,通常简称为OSIV(Open Session In View)模式。 OSIV模式的核心思想是在Controller层和View层之间保持...

    Hibernate事务管理.

    Open Session In View模式就是为了应对这个问题而设计的。它在请求开始时打开Session,并将其绑定到当前线程,确保在整个HTTP请求生命周期内Session都是活跃的。这样,即使在视图层(例如JSP页面)中,也可以安全地...

    Spring延迟加载和声明式事务处理最终解决方案(修正版)

    Spring框架的延迟加载和声明式事务处理是两个关键特性,...通过合理地使用Open Session in View机制,可以解决延迟加载时Session关闭导致的问题,同时,声明式事务处理则简化了事务管理,提升了应用的效率和可扩展性。

    Struts Spring Hibernate 整合 OpenSessionInView 例子

    为了练手培训,给大家准备的 Open Session In View 的简单例子,纯代码,大家可以参考,其中主要说了六部分内容: 1.通过接口编程 2.通过spring注入dao到 action 3.通过 open session in view filter 支持 延迟加载...

    ssh中getCurrentSession的使用

    - 首先,需要配置Hibernate,让其知道如何初始化SessionFactory,并启用Open Session In View模式。 - 在业务逻辑代码中,通过SessionFactory实例调用`getCurrentSession()`,然后执行数据库操作。 - 为了处理...

    集成spring的hibernate懒加载

    在Spring整合Hibernate的情况下,Session通常通过Transaction Management进行管理,比如使用`Open Session in View`(OSIV)模式或者基于注解的事务管理。 当你尝试在Controller层或者视图层访问懒加载的属性时,...

    open62541开发文档

    服务部分(Services)会介绍OPC UA的各种服务,如Secure Channel(安全通道服务集)、Session(会话服务集)、Discovery(发现服务集)、NodeManagement(节点管理服务集)、View(视图服务集)、Query(查询服务集...

    ssh_inte2模板常用方法&延迟加载问题

    可以考虑将事务范围扩大,或者使用开放Session视图模式(Open Session In View,OSIV),让Session贯穿整个HTTP请求,但请注意,OSIV模式可能导致更多的并发问题,需要谨慎使用。 3. **使用Eager Loading**:如果...

    Android google io 2012 opensource已通过编译无错误

    View detailed session, code lab, and speaker information, including speaker bios, photos, and Google+ profiles +1 sessions right from the app Participate in public #io12 conversations on Google+ Guide...

    课程hibernate的事务和并发.pdf

    这种方式被称为ThreadLocal Session和Open Session in View模式,能够简化事务和Session的生命周期管理。 在实际应用中,需要确保正确地开启和结束Session及事务,并将其与数据访问操作结合。HibernateUtil类可以...

    UG Open API 二次开发

    - 在UG的界面环境(session)下运行。 - 程序被加载到UG的运行空间中(由UG分配的内存)。 - 特点包括执行代码小、连接速度快等。 - 入口函数通常是`ufusr`或`ufsta`。 - 示例代码结构如下: ```c #include...

    hello_xr_hpp:OpenXR“ hello_xr”示例的端口到OpenXR-Hpp绑定投影

    OpenXR的核心组件包括实例(Instance)、系统(System)、会话(Session)、视图配置(View Configuration)、交换图像(Swapchain)和动作(Action)。在C++中,这些都由对应的类表示,如`xr::Instance`, `xr::...

    【北大青鸟内部教程】jsp中关于Hibernate延时加载的问题

    为解决此问题,可以在Controller层或Service层提前加载关联数据,或者使用Hibernate的“开放Session视图”(Open Session in View)模式。 3. **事务管理**:延时加载需要在一个有效的Hibernate Session内进行。在...

Global site tag (gtag.js) - Google Analytics