这次做一个项目,用上了OpenSessionInViewFilter这个过滤器,以前就知道使用它可以把session一直绑定在整个request请求之上,以前也有试过,但是之前的项目没有使用到事务,所以一直会有问题,后来查了网上看到说这个使用过滤器一定要配置事务所以就放弃了。
这次做的项目,框架比较严谨,采用典型的三层结构,也在service层配置了spring注解式事务,接着就把OpenSessionInViewFilter用上去了,效果挺好的,显然比关闭延迟加载的效率会高很多。配置很简单:
<filter>
<filter-name>hibernateFilter</filter-name>
<filter-class>
org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
但是做着做着就发现了一个问题,我们的框架模仿了struts2的paramsPrepareParams拦截器栈的执行方式,会在提交保存表单的请求时,从请求中取出ID值,然后根据这个ID查找数据库中的对象,接着再用请求中的参数覆盖这个对象属性,再把对象传到Service层中进行处理。当然在保存这个对象之前还必须进行一些逻辑校验,在通过后才保存到数据库。问题就出来,我们发现不管是否校验通过,这个对象都被修改了。代码大概是这样的:
Foo foo = ...;
if(check(foo)){
dao.saveOrUpdate(foo);
return 0;
}else{
log.error(...);
return 1;
}
排查的时候我们一想就猜到问题可能出在OpenSessionInViewFilter之上,由于从最早的去数据库中查询这个对象开始,session就一直没有关闭,即使到了service层,这个对象仍然是出于托管状态,那不管是否显示调用了saveOrUpdate方法,由于hibernate会进行脏检查,所以修改都会发生。后面我们想了几个方案:
- 最土的一个,取出这个对象后,把这个对象给clone一份,然后操作这个clone的对象,还要注意修改的时候不能使用update方法而要改用merge方法,否则会报错,异常信息为"org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session",这个方法倒是让我学到了一种不用clone方法clone对象的方式~~
- 关闭hibernate的脏检查,可以通过session.setReadOnly(data, true),但是要确实修改的时候必须调用session.setReadOnly(data, false),还要在这行调用之后做一次修改对象的方法(调用对象的某个属性的set方法)。
- 在最早的数据库取出需要的持久化对象后,就手工脱管,这可以通过session.evit(data)。
- 使用OpenSessionInViewFilter之前做个判断,让修改和保存的方法都不经过这个过滤器,通过附加参数来实现。
最后我们选择了最后一种,因为对代码的改动量最少。过了一阵子,轻松下来后又想到这个问题,想看看这个过滤器到底是怎么实现的,于是乎,打开docjar,查了OpenSessionInViewFilter的源码,首先看到注释说这个过滤器可以用在没有事务的环境中:It is suitable for service layer transactions via org.springframework.orm.hibernate3.HibernateTransactionManager or org.springframework.transaction.jta.JtaTransactionManager as well as for non-transactional execution (if configured appropriately)。这里要说明一点,网上有的文章说OpenSessionInViewFilter不能用于非事务环境中,还贴出了部分源码,但是我比较了两份源码,发现不同,可能是版本的问题。
接着看下去,发现我配置的方式默认为single session mode,这时Hibernate FlushMode默认为NEVER(MANUAL),但是在事务之中会把它暂时性的修改为AUTO,我就在想会不会是由于这个原因造成的,查了资料,无关。倒是后来让我搞明白了该如何在非事务的环境中使用OpenSessionInViewFilter,应该这样配置:
<filter>
<filter-name>hibernateFilter</filter-name>
<filter-class>
org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
</filter-class>
<init-param>
<param-name>flushMode</param-name>
<param-value>AUTO</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
有一天突然灵感闪现,想起来Spring的事务回滚原则,默认在抛出运行时异常的时候,事务就会被回滚。马上试了一下,创建个自定义异常类,在逻辑判断错误的地方,抛出这个异常,现在代码看起来就像这样:
Foo foo = ...;
if(check(foo)){
dao.saveOrUpdate(foo);
}else{
throw new CustomeException(...);
}
果然可以了!这同时让我想到以前有个朋友问我,他看到书上网上很多源码在检查错误的时候都抛出一个异常,搞不懂这样比返回一个错误代码好在什么地方?我那时也说不出个所以然来,只觉得如果有方法本身有返回值的时候就不好办了。现在我又找到一个原因了。
分享到:
相关推荐
2. **Hibernate配置**:使用`OpenSessionInViewFilter`过滤器,该过滤器使得Hibernate在HTTP请求的生命周期内保持一个数据库会话,解决了懒加载(Lazy Loading)时可能出现的错误。`hibernateFilter`将这个过滤器...
### Spring监听器与过滤器详解:关键代码与实践应用 #### 标题解析与核心概念 标题“spring监听器”指向了Spring框架中一个重要的组件——监听器(Listener)。Spring框架不仅在Java企业级开发中提供了强大的依赖...
**S2SH集成详解** ...总的来说,这个S2SH集成案例涵盖了Web应用开发的关键技术,从用户交互到数据持久化,再到事务管理,为初学者提供了一个完整的实践平台,有助于深入理解和掌握Java Web开发的核心概念。
"我的智囊团(SSH)_04_开发提问及回复功能_上"这个项目...总的来说,这个项目实战涵盖了SSH框架的使用、数据库交互、错误处理、日志记录以及用户输入验证等核心知识点,是学习和提升Web应用开发技能的一个实践案例。
Spring框架下的`OpenSessionInViewFilter`是一个典型例子,只需在`web.xml`中进行配置即可轻松实现。 四、最佳实践与注意事项 - **细粒度控制**:确保Session和事务的控制符合应用的具体需求,避免不必要的资源浪费...
### 基于全注解方式的SSH基础框架解析 ...它使用最新的技术版本,并且采用了最佳实践来优化性能和简化开发流程。对于想要快速搭建一个稳定可靠的Web应用程序的开发者来说,这是一个非常好的起点。
### Spring学习笔记知识点详解 #### 一、面向接口(抽象)编程的概念与好处 面向接口编程是一种编程方式,强调在设计系统时...通过深入理解这些知识点,可以帮助开发者更好地掌握 Spring 框架的核心原理和技术实践。
- **最佳实践**:在开发过程中遵循一定的编码规范和设计模式,如MVC模式,可以使代码更加清晰易维护。 - **性能优化**:关注系统性能,适时使用缓存技术,合理配置数据库连接池等,都是提升应用性能的有效手段。
Java Servlet过滤器是Java Web应用程序中的重要组件,它在请求被Servlet处理之前和响应返回给客户端之后进行拦截,可以用于实现各种...在实践中,结合`web.xml`和自定义过滤器类,我们可以构建出强大且灵活的应用架构。
session缓存的作用域可根据配置延长至jsp和action,通过`openSessionInViewFilter`实现;查询缓存用于提高频繁查询的效率,尤其适用于更新较少的场景。 **Java内存管理**分为持久化内存(perm)和非持久化内存。...
通过以上分析,可以看出文档内容主要涉及到了JavaEE Web应用开发过程中经常碰到的问题及其解决方法,尤其强调了与Hibernate框架结合使用时需要注意的一些细节和最佳实践。理解这些知识点有助于提高开发效率并避免...
- **OpenSessionInViewFilter**:此过滤器确保在视图渲染过程中保持一个打开的Hibernate Session,这对于事务管理和延迟加载特别有用。 #### 2. struts-config.xml的配置调整 在Struts配置文件中,为了与Spring...
- 配置`OpenSessionInViewFilter`过滤器,使得Hibernate会话与HTTP请求绑定在一起,便于处理数据库操作。 - 指定自定义的`struts.xml`文件位置,以及指定Struts2 Action的扫描路径。 - 配置Proxool的可视化监控...
### Struts2、Spring与Hibernate整合的关键点及注意事项 #### 一、概述 ...通过合理地配置各种配置文件并遵循一定的最佳实践,可以有效地实现这三个框架的无缝集成,从而构建出高效稳定的Web应用程序。
### Struts2.1 + Spring3.0 + Hibernate3.3 整合实践 #### 一、项目背景与概述 在Java Web开发中,Struts2、Spring与Hibernate是三个非常重要的框架,它们分别用于处理MVC架构中的表示层、业务逻辑层与数据访问层...
在web.xml中配置Spring的监听器ContextLoaderListener以初始化Spring应用上下文,并通过OpenSessionInViewFilter来处理可能出现的SessionFactory问题,确保在Controller和Service之间保持有效的Hibernate Session。...
本文将详细地介绍如何从零开始搭建一个完整的SSH框架,并为初学者提供一套可参照的实践指南。 #### 二、准备工作 1. **安装Eclipse或IntelliJ IDEA**:作为开发环境的基础工具。 2. **安装JDK**:确保系统已经正确...
- **临潼德荥纸业有限公司客户管理系统**:这个项目中,黄先生使用了Struts2+Spring+Hibernate,涉及到客户资源管理、服务跟踪等模块,他采用了懒加载优化和Spring的OpenSessionInViewFilter来解决懒加载问题。...
在Web应用中,为了确保每次请求都能获得新的Session,通常会配置openSessionInViewFilter,保证数据操作的正确性。 整合SSH的步骤如下: 1. 引入SSH相关的jar包,确保版本兼容。Struts和Hibernate的jar包可以从IDE...
它提供了一个全面的基础设施,简化了应用程序的开发,并鼓励良好的编程实践。以下是对Spring框架及其核心特性的详细解释。 1. **Spring的优点** - **分层架构**:Spring通过模块化的结构,允许开发者仅使用所需的...