`
daweiangel
  • 浏览: 325757 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类

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);
}    
可以看到OpenSessionInViewFilter在getSession的时候,会把获取回来的session的flush mode 设为FlushMode.NEVER。
然后把该sessionFactory绑定到TransactionSynchronizationManager,使request的整个过程都使用同一个session,
在请求过后再接除该sessionFactory的绑定,最后closeSessionIfNecessary根据该session是否已和transaction绑定来决定是否关闭session

。在这个过程中,若HibernateTemplate 发现自当前session有不是readOnly的transaction,就会获取到FlushMode.AUTO Session,使方法拥

有写权限。

public static void closeSessionIfNecessary(Session session, SessionFactory sessionFactory)      throws

CleanupFailureDataAccessException
{  
if (session == null || TransactionSynchronizationManager.hasResource(sessionFactory)) {    
return;  
}  
logger.debug("Closing Hibernate session");  
try {    
session.close();  
}  
catch (
JDBCException ex)
{    
// SQLException underneath    
throw new CleanupFailureDataAccessException("Could not close Hibernate session", ex.getSQLException());  

catch (HibernateException ex)
{    
throw new CleanupFailureDataAccessException("Could not close Hibernate session", ex);  
}
}   
也即是,如果有不是readOnly的transaction就可以由Flush.NEVER转为Flush.AUTO,拥有insert,update,delete操作权限,如果没有

transaction,并且没有另外人为地设flush model的话,则doFilter的整个过程都是Flush.NEVER。所以受transaction保护的方法有写权限,

没受保护的则没有。

采用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是个双刃剑,放在公网上内容多流量大的网站请慎用
分享到:
评论

相关推荐

    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

    这个问题通常是由于在`Open Session In View`模式下执行了写操作导致的。因为`Open Session In View`默认采用`FlushMode.NEVER`,这意味着Hibernate不会自动刷新session来同步数据库的变化。为了避免这个问题,可以...

    niUsrp Open Rx Session_open_LabVIEWRX_labview_

    在LabVIEW中,niUSRP Open Rx Session主要指的是建立一个接收(Rx)会话的过程,用于从USRP设备接收射频信号。这个过程通常包括以下步骤: 1. **硬件配置**:首先,需要设置USRP硬件参数,如中心频率、采样率、带宽...

    session丢失解决方案

    重定向的时候是有session丢失的问题;window.open丢失session问题;使用框架(Frameset)调用不同域名下的页面,会出现此域下页面的Cookies和Session丢失的现象。

    Advances and Open Problems in Federated Learning.pdf

    Advances and Open Problems in Federated Learning。Federated learning (FL) is a machine learning setting where many clients (e.g. mobile devices or whole organizations) collaboratively train a model ...

    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层之间保持...

    Open IFrame In News Table.crx

    Open IFrame In News Table 一款Chrome扩展插件,通过该插件可以右键将网页嵌入的 IFrame 框架 快速使用 新tab 页签打开。

    oracle参数open_cursors与session_cached_cursors详解.pdf

    Oracle 数据库中,open_cursors 和 session_cached_cursors 是两个重要的参数,它们对 Oracle 的运行性能产生了直接的影响。本文将详细解释这两个参数的作用机理及其异同点,并探讨如何监控和调整它们的设定值,以...

    osiv-reproducer:与spring.jpa.open-in-view和JDBCTemplate一起意外问题的最小复制者

    带有spring.jpa.open-in-view和JDBCTemplate的意外问题的复制者这个仓库是一个最小的Spring Boot应用程序,可以重现我在spring.jpa.open-in-view设置为true的真实应用程序中遇到的问题(如果Spring Boot JPA Starter...

    使用Spring引起的错误

    当使用Open Session In View模式时,如果Session的Flush Mode被设置为NEVER,并且尝试执行写操作(如更新或删除),就会触发“Write operations are not allowed in read-only mode (FlushMode.NEVER)”这个异常。...

    Openai Api开发文档 - Openai Api中文文档 - Openai Api中英双语文档

    Openai Api开发文档 | Openai Api中文文档 | Openai Api中英双语文档 ChatGPT是由OpenAI开发的一个人工智能聊天机器人程序,于2022年11月推出。该程序使用基于GPT-3.5架构的大型语言模型并通过强化学习进行训练。 ...

    java后台请求http并保持Session

    下面将详细讲解这个过程,包括GET和POST方法的使用,以及Session管理。 首先,我们需要了解HTTP协议。HTTP是超文本传输协议,用于在Web上交换信息。它有两种主要的方法:GET和POST。GET方法用于获取资源,参数通过...

    删除右键菜单中open in visual studio

    下载此文件,然后直接双击运行,就可以去掉右键菜单中的“open in visual studio"选项

    osgi session共享 支持springmvc 配置个filter即可

    标题中的“osgi session共享 支持springmvc 配置个filter即可”表明我们要讨论的是在OSGi(Open Service Gateway Initiative)环境中,如何通过Spring MVC并利用Filter来实现多个服务之间的Session共享。OSGi是一种...

    通过HttpURLConnection获取SESSIONID

    //得到Cookie的所有内容,包括SESSIONID,在进行下次提交的时候 直接把这个Cookie的值设到头里头就行了 //淡然只得到SESSIONID也很简单的 ,但是有时候Set-Cookie的值有几个的 List&lt;String&gt; list = (List) ...

    PHP基于memcahe的session方法重写

    这个类需要实现`session_set_save_handler`中的几个回调函数:`open`, `close`, `read`, `write`, `destroy`, 和 `gc`。 - `open`: 打开session存储。在这个函数中,可以初始化与memcache服务器的连接。 - `close...

    处理session跨域几种方案

    处理Session跨域问题通常涉及到多个网站或应用之间共享用户身份验证信息。Session是Web应用程序用来存储用户特定数据的一种机制,通常存储在服务器端,而Session ID通过Cookie在客户端与服务器之间传递。当用户在...

Global site tag (gtag.js) - Google Analytics