在没有使用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 (OSIV) 模式是一种在基于Hibernate的Web应用程序中处理持久化数据的策略,它允许在视图层(例如JSP页面)中安全地访问延迟加载的对象,而无需担心Session已关闭的问题。以下是关于这个模式及其...
在这个小项目中,"Open Session in View"(OSIV)模式被采用,这是一种处理持久化数据的策略,以避免在Web应用中出现常见的并发问题,如数据不一致和懒加载异常。 Struts2是一个强大的MVC框架,它提供了一种灵活的...
这个问题通常是由于在`Open Session In View`模式下执行了写操作导致的。因为`Open Session In View`默认采用`FlushMode.NEVER`,这意味着Hibernate不会自动刷新session来同步数据库的变化。为了避免这个问题,可以...
在LabVIEW中,niUSRP Open Rx Session主要指的是建立一个接收(Rx)会话的过程,用于从USRP设备接收射频信号。这个过程通常包括以下步骤: 1. **硬件配置**:首先,需要设置USRP硬件参数,如中心频率、采样率、带宽...
重定向的时候是有session丢失的问题;window.open丢失session问题;使用框架(Frameset)调用不同域名下的页面,会出现此域下页面的Cookies和Session丢失的现象。
【前端开源库-open-in-editor】是一个专为前端开发者设计的实用工具库,它允许用户直接在他们的代码编辑器中打开项目文件,极大地提高了开发效率。这个库的核心功能是通过一个简单的命令或者点击操作,将浏览器中的...
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 ...
3. **Open Session in View (OSIV)**:在视图渲染阶段保持Session打开,以允许最后时刻的懒加载,但需要注意防止Session泄露。 总的来说,Hibernate中Session的管理是保证多线程环境下数据一致性的重要环节。...
3. **Open Session in View(OSIV)模式** OSIV模式旨在解决Web应用中,由于用户请求可能会引发多次数据库操作,而这些操作可能跨多个HTTP请求。在这种模式下,Session在整个HTTP请求周期内保持打开状态,直到请求...
为了解决这个问题,Spring提供了一个过滤器 `OpenSessionInViewFilter` 或者 `OpenSessionInViewInterceptor`,通常简称为OSIV(Open Session In View)模式。 OSIV模式的核心思想是在Controller层和View层之间保持...
【标题】"vmware-view-open-client_4.0.0-215529+dfsg.orig" 提供的是VMware View的开源客户端版本,这是一款强大的虚拟桌面基础设施(VDI)解决方案,专为远程访问和管理虚拟桌面设计。在4.0.0这个特定的版本中,它...
Open IFrame In News Table 一款Chrome扩展插件,通过该插件可以右键将网页嵌入的 IFrame 框架 快速使用 新tab 页签打开。
Oracle 数据库中,open_cursors 和 session_cached_cursors 是两个重要的参数,它们对 Oracle 的运行性能产生了直接的影响。本文将详细解释这两个参数的作用机理及其异同点,并探讨如何监控和调整它们的设定值,以...
带有spring.jpa.open-in-view和JDBCTemplate的意外问题的复制者这个仓库是一个最小的Spring Boot应用程序,可以重现我在spring.jpa.open-in-view设置为true的真实应用程序中遇到的问题(如果Spring Boot JPA Starter...
Openai Api开发文档 | Openai Api中文文档 | Openai Api中英双语文档 ChatGPT是由OpenAI开发的一个人工智能聊天机器人程序,于2022年11月推出。该程序使用基于GPT-3.5架构的大型语言模型并通过强化学习进行训练。 ...
openeuler双网卡绑定
当使用Open Session In View模式时,如果Session的Flush Mode被设置为NEVER,并且尝试执行写操作(如更新或删除),就会触发“Write operations are not allowed in read-only mode (FlushMode.NEVER)”这个异常。...
下面将详细讲解这个过程,包括GET和POST方法的使用,以及Session管理。 首先,我们需要了解HTTP协议。HTTP是超文本传输协议,用于在Web上交换信息。它有两种主要的方法:GET和POST。GET方法用于获取资源,参数通过...
下载此文件,然后直接双击运行,就可以去掉右键菜单中的“open in visual studio"选项
标题中的“osgi session共享 支持springmvc 配置个filter即可”表明我们要讨论的是在OSGi(Open Service Gateway Initiative)环境中,如何通过Spring MVC并利用Filter来实现多个服务之间的Session共享。OSGi是一种...