码迷,mamicode.com
首页 > Web开发 > 详细

详解Hibernate中的NoSession问题

时间:2015-08-21 11:27:56      阅读:169      评论:0      收藏:0      [点我收藏+]

标签:

 

 1.前言

今天在整合SSH框架的时候,当在表现层调用bean层查找数据的时候,报错,具体如下所示

技术分享


根据字面上的意思,应该是代理不能被初始化,session已经关闭,这篇博客就来解决一下这个问题。


 2.NoSession问题

1.原因分析

当执行Session的load()方法时,Hibernate不会立即执行查询CUSTOMERS表的select语句,仅仅返回Customer类的代理类的实例,这个代理类具由以下特征: 

(1)由Hibernate在运行时动态生成,它扩展了Customer类,因此它继承了Customer类的所有属性和方法,但它的实现对于应用程序是透明的。 
(2)当Hibernate创建Customer代理类实例时,仅仅初始化了它的OID属性,其他属性都为null,因此这个代理类实例占用的内存很少。 
(3)当应用程序第一次访问Customer代理类实例时(例如调用customer.getXXX()或customer.setXXX()方法),Hibernate会初始化代理类实例,在初始化过程中执行select语句,真正从数据库中加载Customer对象的所有数据。但有个例外,那就是当应用程序访问Customer代理类实例的getId()方法时,Hibernate不会初始化代理类实例,因为在创建代理类实例时OID就存在了,不必到数据库中去查询。 

提示:Hibernate采用CGLIB工具来生成持久化类的代理类。CGLIB是一个功能强大的Java字节码生成工具,它能够在程序运行时动态生成扩展 Java类或者实现Java接口的代理类。关于CGLIB的更多知识,请参考: 

Spring学习笔记五(JDKProxy和cglibProxy的区别)



因此从字面上我们了解到是在表现层调用的时候,session已经关闭。因为Hibernate中如果采用load加载的话,默认的是延迟加载,也就是lazy=true操作,因此,当调用完load后,session即可关闭,如果此时再次打印输出值得话,就会报上面的错误,因为我们的session只是放置到了Dao层。表现层根本获取不到。

public void load() {
		//调用延迟加载
		User user1 = userService.getById(1);
		//下面这句话就报错
		System.out.println(user1.getName());
		System.out.println("----------------------");
		User user2 = userService.getById(1);
		System.out.println(user2.getName());
		System.out.println("----------------------");
	}


2.方法一

既然已经分析出来是延迟加载的原因,因此我们可以关闭延迟加载的属性,也就是不延迟加载lazy=false,但是只有确定了该业务不需要延迟加载的时候,才考虑这种设计。这是一种解决的办法,但是有点死板,把这么好的延迟加载的特性给活生生的去除了。

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
                                   "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.tgb.itoo.base.entity">
<!-- 去除延迟加载的属性 -->
 <class name="User" table="test_user" lazy="false" >
  <id name="id">
   <generator class="native"/>
  </id>
  <property column="name" generated="never" lazy="false" length="255"
   name="name" type="string"/>
 </class>
</hibernate-mapping>



3.方法二

我们可以把session的生命周期放置到表现层,这样的话,就可以在应用延迟加载特性下,也可以获取想要的数据。这时通常采取的操作时OpenSessionView,在表现层的web.xml中进行配置即可

<filter>
<filter-name>openSessionInView</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>openSessionInView</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

4.方法三

第一种办法,采取的是关闭全局的延迟加载,有点太死板。在hibernate中我们可以根据我们的业务需要动态的关闭延迟加载的属性。采取的操作就是Hibernate.initialize(user);但在使用时需要注意的一点是:其中的proxy是持久对象的关联对象属性,比如A实体,你要把A的关联实体B也检出,则要写Hibernate.initialize(a.b)。

public User getById(int id) {
		User user = userEao.getById(id);
		Hibernate.initialize(user);
		return user;
	}




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

详解Hibernate中的NoSession问题

标签:

原文地址:http://blog.csdn.net/luckyzhoustar/article/details/47829947

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!