Spring 为我们提供了一个叫做 OpenSessionInViewFilter 的过滤器,他是标准的 Servlet Filter 所以我们把它按照规范配置到 web.xml 中方可使用。使用中我们必须配合使用 Spring 的 HibernateDaoSupport 来进行开发,也就是说,我们的dao层的类都要继承于 HibernateDaoSupport,从中由 Spring 来控制 Hibernate 的 Session 在请求来的时候开启,走的时候关闭,保证了我们访问数据对象时的稳定性。

  1. 在 web.xml 中加入对应过滤器配置文件

  1. <!-- Spring的OpenSessionInView实现 -->
  2. <filter>
  3. <filter-name>openSessionInViewFilter</filter-name>
  4. <filter-class>        org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
  5. </filter-class>
  6. <!-- singleSession默认为true,若设为false则等于没用OpenSessionInView 。所以默认可以不写-->
  7. <init-param>
  8. <param-name>singleSession</param-name>
  9. <param-value>true</param-value>
  10. </init-param>
  11. <!--
  12. 指定org.springframework.orm.hibernate3.LocalSessionFactoryBean在spring配置文件中的名称,默认值为sessionFactory。 如果LocalSessionFactoryBean在spring中的名称不是sessionFactory,该参数一定要指定,否则会出现找不到sessionFactory的例外。所以默认可以不写
  13. -->
  14. <init-param>
  15. <param-name>sessionFactoryBean</param-name>
  16. <param-value>sessionFactory</param-value>
  17. </init-param>
  18. </filter>
  19. <filter-mapping>
  20. <filter-name>openSessionInViewFilter</filter-name>
  21. <url-pattern>/*</url-pattern>
  22. </filter-mapping>

 2. 在我们访问持久层数据是使用 Spring 为我们的 HibernateDaoSupport 的支持,并使用其中的对应方法操作我们的持久层数据

  1. import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
  2. public class XxxDAO extends HibernateDaoSupport {
  3. public void save(Xxx transientInstance) {
  4. try {
  5. getHibernateTemplate().save(transientInstance);
  6. } catch (RuntimeException re) {
  7. throw re;
  8. }
  9. }
  10. }

OpenSessionInViewFilter的主要功能是用来把一个Hibernate Session和一次完整的请求过程对应的线程相绑定。Open Session In View在request把session绑定到当前thread期间一直保持hibernate session在open状态,使session在request的整个期间都可以使用,如在View层里PO也可以lazy loading数据,如 ${ company.employees }。当View 层逻辑完成后,才会通过Filter的doFilter方法或Interceptor的postHandle方法自动关闭session。

  很多人在使用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里的几个方法:

  1. protected void doFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain filterChain)
  2. throws ServletException, IOException {
  3.  SessionFactory sessionFactory = lookupSessionFactory();
  4.  logger.debug("Opening Hibernate Session in OpenSessionInViewFilter");
  5.  Session session = getSession(sessionFactory);
  6.  TransactionSynchronizationManager.bindResource(
  7.  sessionFactory, new SessionHolder(session));
  8. try {
  9. filterChain.doFilter(request, response);
  10. }
  11. finally {
  12.    TransactionSynchronizationManager.unbindResource(sessionFactory);
  13. logger.debug("Closing Hibernate Session in OpenSessionInViewFilter");
  14. closeSession(session, sessionFactory);
  15.  }
  16. }
  1. protected Session getSession(SessionFactory sessionFactory)
  2. throws DataAccessResourceFailureException {
  3. Session session = SessionFactoryUtils.getSession(sessionFactory, true);
  4.   session.setFlushMode(FlushMode.NEVER);
  5.   return session;
  6. }
  1. protected void closeSession(Session session, SessionFactory sessionFactory)
  2. throws CleanupFailureDataAccessException {
  3.   SessionFactoryUtils.closeSessionIfNecessary(session, sessionFactory);
  4. }

 可以看到OpenSessionInViewFilter在getSession的时候,会把获取回来的session的flush mode 设为FlushMode.NEVER。然后把该sessionFactory绑定到 TransactionSynchronizationManager,使request的整个过程都使用同一个session,在请求过后再解除该 sessionFactory的绑定,最后closeSessionIfNecessary根据该 session是否已和transaction绑定来决定是否关闭session。在这个过程中,若HibernateTemplate 发现自当前session有不是readOnly的transaction,就会获取到FlushMode.AUTO Session,使方法拥有写权限。

  1. public static void closeSessionIfNecessary(Session session, SessionFactory  sessionFactory)
  2. throws CleanupFailureDataAccessException {
  3. if (session == null ||
  4. TransactionSynchronizationManager.hasResource(sessionFactory)) {
  5. return;
  6. }
  7. logger.debug("Closing Hibernate session");
  8. try {
  9. session.close();
  10. }
  11. catch (JDBCException ex) {
  12. // SQLException underneath
  13. throw new CleanupFailureDataAccessException("Could not close Hibernate session", ex.getSQLException());
  14. }
  15. catch (HibernateException ex) {
  16. throw new CleanupFailureDataAccessException("Could not close Hibernate session",  ex);
  17. }
  18. }

也即是,如果有不是readOnly的transaction就可以由Flush.NEVER转为Flush.AUTO,拥有 insert,update,delete操作权限,如果没有transaction,并且没有另外人为地设flush model的话,则doFilter的整个过程都是Flush.NEVER。所以受transaction保护的方法有写权限,没受保护的则没有。

解决:

采用spring的事务声明,使方法受transaction控制

  1. <bean id="baseTransaction"
  2. class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
  3. abstract="true">
  4. <property name="transactionManager" ref="transactionManager"/>
  5. <property name="proxyTargetClass" value="true"/>
  6. <property name="transactionAttributes">
  7. <props>
  8. <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
  9. <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
  10. <prop key="load*">PROPAGATION_REQUIRED,readOnly</prop>
  11. <prop key="save*">PROPAGATION_REQUIRED</prop>
  12. <prop key="add*">PROPAGATION_REQUIRED</prop>
  13. <prop key="update*">PROPAGATION_REQUIRED</prop>
  14. <prop key="remove*">PROPAGATION_REQUIRED</prop>
  15. </props>
  16. </property>
  17. </bean>
  18. <bean id="userService" parent="baseTransaction">
  19. <property name="target">
  20. <bean class="com.phopesoft.security.service.impl.UserServiceImpl"/>
  21. </property>
  22. </bean>

对于上例,则以save,add,update,remove开头的方法拥有可写的事务,如果当前有某个方法,如命名为importExcel(),则因没有transaction而没有写权限,这时若方法内有insert,update,delete操作的话,则需要手动设置flush model为Flush.AUTO,如

1  session.setFlushMode(FlushMode.AUTO);

2  session.save(user);

3  session.flush();

或可以

在web.xml中过滤器openSession修改初始参数:

  1. <!-- 在项目中使用Spring+Hibernate的时候,会开启OpenSessionInViewFilter来阻止延迟加载的错误,但是在我们开启OpenSessionInViewFilter这个过滤器的时候FlushMode就已经被默认设置为了MANUAL,如果FlushMode是MANUAL或NEVEL,在操作过程中 hibernate会将事务设置为readonly,所以在增加、删除或修改操作过程中-->
  2. lt;init-param>
  3. <param-name>flushMode</param-name>
  4. <param-value>AUTO</param-value>
  5. </init-param>

  从上述代码其实可以得到一些对我们的开发有帮助的结论: 
  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.javaeye.com/topic/15057

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

  3. 由于使用了OpenSessionInView模式后造成了内存和数据库连接问题 
  这个问题是我在生产环境中碰到的一个问题。由于使用了OpenSessionInView模式,Session的生命周期变得非常长。虽然解决了Lazy

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

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

  最后提一下OpenSessionInView模式的一些替代方案,

1

可以使用OpenSessionInViewInterceptor来代替这个Filter,此时可以使用Spring的AOP配置,将这个Interceptor配置到你所需要的层次上去。

在application.xml配置

  1. <!-- Spring的OpenSessionInView实现 -->
  2. <filter>
  3. <filter-name>openSessionInViewFilter</filter-name>
  4. <filter-class>
  5. org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
  6. </filter-class>
  7. </filter>
  8. <filter-mapping>
  9. <filter-name>openSessionInViewFilter</filter-name>
  10. <url-pattern>/*</url-pattern>
  11. </filter-mapping>

2

使用最古老的Hibernate.initialize()方法进行初始化了。

 
 
 
G
M
T
 
检测语言
世界语
中文简体
中文繁体
丹麦语
乌克兰语
乌兹别克语
乌尔都语
亚美尼亚语
伊博语
俄语
保加利亚语
僧伽罗语
克罗地亚语
冰岛语
加利西亚语
加泰罗尼亚语
匈牙利语
南非祖鲁语
卡纳达语
印地语
印尼巽他语
印尼爪哇语
印尼语
古吉拉特语
哈萨克语
土耳其语
塔吉克语
塞尔维亚语
塞索托语
威尔士语
孟加拉语
宿务语
尼泊尔语
巴斯克语
布尔语(南非荷兰语)
希伯来语
希腊语
德语
意大利语
意第绪语
拉丁语
拉脱维亚语
挪威语
捷克语
斯洛伐克语
斯洛文尼亚语
斯瓦希里语
旁遮普语
日语
格鲁吉亚语
毛利语
法语
波兰语
波斯尼亚语
波斯语
泰卢固语
泰米尔语
泰语
海地克里奥尔语
爱尔兰语
爱沙尼亚语
瑞典语
白俄罗斯语
立陶宛语
索马里语
约鲁巴语
缅甸语
罗马尼亚语
老挝语
芬兰语
苗语
英语
荷兰语
菲律宾语
葡萄牙语
蒙古语
西班牙语
豪萨语
越南语
阿塞拜疆语
阿尔巴尼亚语
阿拉伯语
韩语
马其顿语
马尔加什语
马拉地语
马拉雅拉姆语
马来语
马耳他语
高棉语
齐切瓦语
  世界语
中文简体
中文繁体
丹麦语
乌克兰语
乌兹别克语
乌尔都语
亚美尼亚语
伊博语
俄语
保加利亚语
僧伽罗语
克罗地亚语
冰岛语
加利西亚语
加泰罗尼亚语
匈牙利语
南非祖鲁语
卡纳达语
印地语
印尼巽他语
印尼爪哇语
印尼语
古吉拉特语
哈萨克语
土耳其语
塔吉克语
塞尔维亚语
塞索托语
威尔士语
孟加拉语
宿务语
尼泊尔语
巴斯克语
布尔语(南非荷兰语)
希伯来语
希腊语
德语
意大利语
意第绪语
拉丁语
拉脱维亚语
挪威语
捷克语
斯洛伐克语
斯洛文尼亚语
斯瓦希里语
旁遮普语
日语
格鲁吉亚语
毛利语
法语
波兰语
波斯尼亚语
波斯语
泰卢固语
泰米尔语
泰语
海地克里奥尔语
爱尔兰语
爱沙尼亚语
瑞典语
白俄罗斯语
立陶宛语
索马里语
约鲁巴语
缅甸语
罗马尼亚语
老挝语
芬兰语
苗语
英语
荷兰语
菲律宾语
葡萄牙语
蒙古语
西班牙语
豪萨语
越南语
阿塞拜疆语
阿尔巴尼亚语
阿拉伯语
韩语
马其顿语
马尔加什语
马拉地语
马拉雅拉姆语
马来语
马耳他语
高棉语
齐切瓦语
         
 
 
 
文本转语音功能仅限200个字符
 
  选项 : 历史 : 反馈 : Donate 关闭

OpenSessionInViewFilter 的配置及替代方案的更多相关文章

  1. OpenSessionInViewFilter 的配置及替代方案(转)

    鸣谢:http://justsee.iteye.com/blog/1174999,http://blog.csdn.net/sunsea08/article/details/4545186 Sprin ...

  2. Spring实战第七章————SpringMVC配置的替代方案

    SpringMVC配置的替代方案 自定义DispatherServlet配置 我们之前在SpittrWebAppInitializer所编写的三个方法仅仅是必须要重载的abstract方法.但还有更多 ...

  3. OpenSessionInViewFilter的配置

    OpenSessionInViewFilter是用来处理懒加载异常的. 懒加载异常的意思的就是:还用不到的东西,就先不加载,等需要的时候再来加载. 所以懒加载对性能有一定的提升,但是,这也会出现一些问 ...

  4. OpenSessionInViewFilter 的配置及作用

    spring为我们解决hibernate的Session的关闭与开启问题. Hibernate 允许对关联对象.属性进行延迟加载,但是必须保证延迟加载的操作限于同一个 Hibernate Sessio ...

  5. OpenSessionInViewFilter 的配置及作用(原文地址: http://blog.csdn.net/sunsea08/article/details/4545186)

    spring为我们解决hibernate的Session的关闭与开启问题. Hibernate 允许对关联对象.属性进行延迟加载,但是必须保证延迟加载的操作限于同一个 Hibernate Sessio ...

  6. 笔记33 Spring MVC的高级技术——Spring MVC配置的替代方案

    一.自定义DispatcherServlet配置  AbstractAnnotationConfigDispatcherServletInitializer所完成 的事情其实比看上去要多.在Spitt ...

  7. opensessioninviewFilter导致org.hibernate.NonUniqueObjectException

    起因: 公司业务需求,增加了一个新的数据源,增加之后,起初一切正常,但是发现后台管理系统所有Ajax请求获取信息没有问题,但是涉及到保存操作就抛出异常. 异常: org.hibernate.NonUn ...

  8. 浅析 SpringMVC 原理和配置.

    一.原理 Spring MVC基于模型-视图-控制器(Model-View-Controller,MVC)模式实现,它能够帮你构建像Spring框架那样灵活和松耦合的Web应用程序,将请求处理的逻辑和 ...

  9. 使用OpenSessionInViewFilter的注意事项

    假设在你的应用中Hibernate是通过spring 来管理它的session.如果在你的应用中没有使用OpenSessionInViewFilter或者OpenSessionInViewInterc ...

随机推荐

  1. Pandas | 06 描述性统计

    有很多方法用来集体计算DataFrame的描述性统计信息和其他相关操作. 其中大多数是sum(),mean()等聚合函数. 一般来说,这些方法采用轴参数,就像ndarray.{sum,std,...} ...

  2. C++各大有名库的介绍——网络通信

    ACE是C++库的代表,超重量级的网络通信开发框架.ACE自适配通信环境(Adaptive Communication Environment)是可以自由使用.开放源代码的面向对象框架,在其中实现了许 ...

  3. 网络协议 7 - UDP 协议

    网络协议五步登天路,我们一路迈过了物理层.链路层,今天终于到了传输层.从这一层开始,很多知识应该都是服务端开发必备的知识了,今天我们就一起来梳理下.     其实,讲到 UDP,就少不了 TCP.这俩 ...

  4. haproxy 配置文件详解 之 frontend

    配置示例: frontend www bind *: mode http option httplog option forwardfor option httpclose log global #a ...

  5. Java通过poi创建Excel文件并分页追加数据

    以下的main函数,先生成一个excel文件,并设置sheet的名称,设置excel头:而后,以分页的方式,向文件中追加数据 maven依赖 <dependency> <groupI ...

  6. 一文带你了解 Flink 的基本组件栈

    作为实时计算领域的佼佼者,Flink 的基本组件同样值得我们仔细研究. Flink 同样遵循着分层的架构设计理念,在降低系统耦合的同时,也为上层用户构建 Flink 应用提供了丰富且友好的接口. Fl ...

  7. thinkphp漏洞如何修复

    THINKPHP漏洞修复,官方于近日,对现有的thinkphp5.0到5.1所有版本进行了升级,以及补丁更新,这次更新主要是进行了一些漏洞修复,最严重的就是之前存在的SQL注入漏洞,以及远程代码执行查 ...

  8. 使用另一个版本的glibc

    glibc是Linux系统的核心库,稍有不慎就会导致系统崩溃.如果在程序中必须使用另一版本的glibc,则需要小心从事.具体来言,是在编译时指定--rpath和--dynamic-linker,而在运 ...

  9. 开源分布式数据库中间件 DBLE

    DBLE 是企业级开源分布式中间件,江湖人送外号 “MyCat Plus”:以其简单稳定,持续维护,良好的社区环境和广大的群众基础得到了社区的大力支持: DBLE官方网站:https://openso ...

  10. 「雅礼集训 2017 Day1」字符串 SAM、根号分治

    LOJ 注意到\(qk \leq 10^5\),我们很不自然地考虑根号分治: 当\(k > \sqrt{10^5}\),此时\(q\)比较小,与\(qm\)相关的算法比较适合.对串\(s\)建S ...