no session or session was closed处理方法

原创 2016年06月02日 10:41:47

首先说明一下,hibernate的延迟加载特性(lazy)。所谓的延迟加载就是当真正需要查询数据时才执行数据加载操作。因为hibernate当中支持实体对象,外键会与实体对象关联起来。如果没有这一特性,当查询某一个含有外键的实体对象时,hibernate会把其他实体对象的数据都查询出来。

简单的来说,当你想查询某个对象时,实际上调用了多条查询语句。有了延迟加载特性,就避免了这种情况的发生,当你真正的使用get另外一个实体对象时,才再执行下面一条查询语句。

但有些时候,这个特性却会给我们应用中带来一些问题。

这个问题相信大家并不陌生了,hibernate的延迟加载(lazy)特性的确不错的优点,如果没了这个特性,我相信大家在处理一些外键的对象时会头大起来,因为效率十分的低。甚至很多人都觉得使用jdbc要比hibernate要高效甚至方便得多,而迫使不去使用hibernate。

我想说,没错,使用jdbc在效率上的确可能要快许多,但差距也不会太大的,因为hibernate本身就支持多种查询方式,SQL、HQL、 DetachedCriteria等。而相反的,hibernate在维护性上比jdbc强很多,因为是实体对象的关系。我相信如果您使用过jdbc来实现注册功能的话,会深有体会。

提示session已关闭(no session or session was closed)

触发这个问题的原因在于,hibernate在查询操作完毕的时候会自动的把session关闭掉,为了降低使用的资源。但问题也这样产生了,不要忘了之前所说的hibernate特性,此时再调用get实体方法的时候就会有可能出现这个错误。因为session已经关闭而不能继续执行查询了。

解决思路:

1、关闭延迟加载特性。

操作起来比较简单,因为hibernate的延迟加载特性是在hbm配置里面可控制的。默认lazy="true",具体配置可以查看一下相关文档,就不详细叙述了。
但使用这个解决办法带来的隐患是十分大的。
首先,出现no session or session was closed就证明了您已经在使用外键关联表,如果去掉延迟加载的话,则表示每次查询的开销都会变得十分的大,如果关联表越多,后果也可以想象得到。所以不建议使用这个方法解决。

2、在session关闭之前把我们想要查询的数据先获取了。

首先需要了解一下session什么时候关闭,也就是它的生命周期。通常情况下hibernate会在查询数据关闭session,而使用getHibernateTemplate().get方法查询后会延迟关闭的时间。会在事务结束后才关闭。

使用拦截器(Interceptor)或过滤器(Filter)控制session。

spring为解决hibernate这一特性提供的解决方案,可以有效的控制session生命周期。

使用这两个方法的详细描述就不多介绍了网上也有不少的文章。这里主要是介绍自己的一套方案。

使用CLONE解决延迟加载问题。

使用Interceptor和Filter,弊端是所有session都一概而论了,无论是否需要延迟session关闭都统统把session关闭的时间延迟了。这里带来了一些资源开销的问题,虽然没必要这么钻牛角尖。但也只是继续本着研究的精神吧。这里的影响程度也是有级别的,因为控制在业务层或者是视图层,影响也有不同的。还有的时候会与其他继承冲突,例如又用了spring的security框架,貌似会有些冲突发生。


在这里想了一下有没有更好的解决办法呢?能在我们需要的时候把数据获取掉,而又不会出现session关闭的情况。

这时我想到了两点,第一,findById方法时候的session会延迟。第二,clone方法。

对于第一点,只能使用get方法来实现也不是绝对的,我们也可以使用DetachedCriteria查询。

第二点有些朋友有些疑问或者陌生,稍微讲解一下。

为什么使用clone?

因为在session关闭之前使用get实体获取的对象没错你也可以查询得到,但是session关闭后,这些数据就不能访问了。如果直接赋值结果还是一样的,因为只是址传递,所以我们必须使用clone方法来把获取后的数据做拷贝操作,而必须还是deep clone,shadow clone也是不行的。


具体操作

1、实现Cloneable接口。

因为我们要进行deep clone操作,所以BO对象必须作以下操作。

implements Cloneable

2、重写(override)clone方法。

clone方法默认为

  1. @Override  
  2. protected Object clone() throws CloneNotSupportedException {   
  3.     return super.clone();   
  4. }  

 

要进行deep clone操作必须把protected改为 public,并且把返回的object改为具体的Bean对象。

3、执行clone操作。

首先,前提当然是确保事务结束之前session未被关闭,可以使用get实体的操作。


然后看下面例子

  1. public List<AccAlias> listAccAlias() {   
  2.     List<AccAlias> all = AccAliasDAO.findAll();   
  3.     if (all != null && !all.isEmpty())   
  4.         for (AccAlias accAlias : all) {   
  5.             try {   
  6.                 Mailbox mailbox = accAlias.getMailbox();   
  7.                 if(mailbox!=null){   
  8.                     mailbox = mailbox.clone();   
  9.                     accAlias.setMailbox(mailbox);   
  10.                 }   
  11.             } catch (CloneNotSupportedException e) {   
  12.                 e.printStackTrace();   
  13.             }   
  14.         }   
  15.     return all;   
  16. }  

 

后续问题研究:

姑且作为一个比较非主流的解决方案吧,是否适合还是要看大家需求的,没有一套方案是绝对适合的。


使用clone解决延迟加载的弊端:

1、clone的实际开销。

2、查询方式的依赖性。必须根据ID查询方式来查询实体。而且更可以认为耦合度提高了,因为业务层clone操作有时必须依赖DAO特定的查询方式。


当然这些弊端也幸好仅仅针对使用到需要解决延迟加载的时候触发。


版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

Hibernate no session or session was closed 解决

虽然说Hibernate的no session已经是一个很老的问题。但是,这个问题无疑是新手最为困扰的事情。 这里将自己如何处理这个问题的解决方法有必要说一下: 之前在web.xml中配置过ope...

解决no session or session was closed的问题

Spring为我们解决Hibernate的Session的关闭与开启问题。  Hibernate 允许对关联对象、属性进行延迟加载,但是必须保证延迟加载的操作限于同一个 Hibernate Sess...
  • JK9700
  • JK9700
  • 2015年09月19日 11:20
  • 1144

过滤器解决Hibernate中(no session or session was closed)异常

简单说一下引起no session or session was closed

有关Hibernate映射关系 no session or session was closed问题解绝方法

运用Spring OpenSessionInViewFilter 解决问题首先要知道程序为什么会报这样的错误? 根据异常提示我们可以定位到懒加载异常问题 使用Spring 来管理session 此时我...

Session was closed解决方案

郁闷两天的事情今天终于被解决了。弄了个example示例查询,组合Requisition(申请表单)属性和Ratify(领导审批)属性查询。每次查询几次就会出现问题。特别是组合没有的实例时就会 浏览器...
  • wgj85
  • wgj85
  • 2008年08月25日 02:08
  • 1561

failed to lazily initialize a collection of role: ......, no session or session was closed

我在用ssh框架编写图书管理系统的时候遇到了这样的错误org.hibernate.LazyInitializationException: failed to lazily initialize a ...

could not initialize proxy - the owning Session was closed解决

其实这个异常写的非常之清楚,就是会话关闭,无法对Hibernate实体进行操作。造成这样的情况有很多,什么书写错误啊,逻辑错误啊,等等.不过,我是因为LAZY.关于lazy机制:延迟初始化错误是运用H...

the vm session was closed before any attempt to power it on

今天启动VBOX出现这个问题”the vm session was closed before any attempt to power it on“ 然后在网上搜索了下,没有满意答案,大多建议重新...

could not initialize proxy - the owning Session was closed

关键字: 异常引起的其实这个异常写的非常之清楚,就是会话关闭,无法对Hibernate实体进行操作。造成这样的情况有很多,什么书写错误啊,逻辑错误啊,等等.不过,偶是因为LAZY.关于lazy机制:延...

myBatis连接MySQL报异常:No operations allowed after connection closed.Connection was i

连接池报错  myBatis连接MySQL报异常:No operations allowed after connection closed.Connection was implici...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:no session or session was closed处理方法
举报原因:
原因补充:

(最多只允许输入30个字)