OpenSessionInView模式的起源:
OpenSessionInViewFilter是Spring提供的一个针对Hibernate的一个支持类,其主要意思是在发起一个页面请求时打开Hibernate的Session,一直保持这个Session,直到这个请求结束,具体是通过一个Filter来实现的。
由于Hibernate引入了Lazy Load特性,使得脱离Hibernate的Session周期的对象如果再想通过getter方法取到其关联对象的值,Hibernate会抛出一个 LazyLoad的Exception。所以为了解决这个问题,Spring引入了这个Filter,使得Hibernate的Session的生命周期变长。
一个简单的例子。
- public void doFilter(ServletRequest request, ServletResponse response,
- FilterChain filterChain) throws IOException, ServletException {
- try{
- Session session=HibernateSessionFactoryUtils.getSession();
- request.setAttribute(HIBERNATE_SESSIN_KEY, session);
- log.debug("客户端请求开始,Hibernate Session已打开.........");
- filterChain.doFilter(request, response);
- }finally {
- Object obj=request.getAttribute(HIBERNATE_SESSIN_KEY);
- if(obj!=null&&obj instanceof Session){
- Session session=(Session)obj;
- session.close();
- log.debug("客户端请求结束,Hibernate Session已关闭.........");
- }else{
- log.error("客户端请求结束,Hibernate Session未发现,请检查代码....");
- }
- }
- }
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
try{
Session session=HibernateSessionFactoryUtils.getSession();
request.setAttribute(HIBERNATE_SESSIN_KEY, session);
log.debug("客户端请求开始,Hibernate Session已打开.........");
filterChain.doFilter(request, response);
}finally {
Object obj=request.getAttribute(HIBERNATE_SESSIN_KEY);
if(obj!=null&&obj instanceof Session){
Session session=(Session)obj;
session.close();
log.debug("客户端请求结束,Hibernate Session已关闭.........");
}else{
log.error("客户端请求结束,Hibernate Session未发现,请检查代码....");
}
}
}
缺点:使用了OpenSessionInView 模式后造成了内存和数据库连接问题
由于使用了OpenSessionInView 模式,Session的生命周期变得非常长。虽然解决了Lazy Load的问题,但是带来的问题就是Hibernate的一级缓存,也就是Session级别的缓存的生命周期会变得非常长,那么如果你在你的 Service层做大批量的数据操作时,其实这些数据会在缓存中保留一份,这是非常耗费内存的。还有一个数据库连接的问题,存在的原因在于由于数据库的 Connection是和Session绑在一起的,所以,Connection也会得不到及时的释放。因而当系统出现业务非常繁忙,而计算量又非常大的时候,往往数据连接池的连接数会不够。这个问题我至今非常头痛,因为有很多客户对数据连接池的数量会有限制,不会给你无限制的增加下去。
在本地开发测试的时候没出现问题,但试想下如果流程中的某一步被阻塞的话,那在这期间connection就一直被占用而不释放。最有可能被阻塞的就是在写Jsp这步,一方面可能是页面内容大,response.write的时间长,另一方面可能是网速慢,服务器与用户间传输时间久。当大量这样的情况出现时,就有连接池连接不足,造成页面假死现象。
解决方案:
1,使用OpenSessionInView Interceptor来代替这个Filter
2,使用Hibernate.initialize()方法初始会延迟加载的对象