详解Hibernate中的NoSession问题

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;
	}

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

时间: 2024-10-09 15:04:36

详解Hibernate中的NoSession问题的相关文章

详解Hibernate中cascade与inverse

学习hibernate的时候对级联关系的概念老是分不清楚,尤其是cascade.inverse傻傻分不清.下面通过例子来简单说明. 准备工作: 首先创建数据库,新建两张表: 教室表classes (字段此处省) 学生表student(字段此处省) 教室与学生是一对多的关系. 然后新建项目,添加hibernate对两张表的支持. 1.cascade cascade表示级联操作,即两个实体间存在级联关系(一个类是另一个类中的属性)时,当保存.更新或删除一个实体时,是否对关联的实体做出相应操作(数据库

详解Hibernate中的一级缓存

1.前言 在Hibernate中有三级缓存,本篇博客先详细的介绍一下,Hibernate中的一级缓存,也就是Session级别的缓存. 2.持久化对象 如果要说到Hibernate的缓存的话,那么首先咱得提一下hibernate中的持久化对象. 其中持久化对象有三种状态,分别是: transient(瞬时态):尚未与Session关联对象,失去引用的话,就会被JVM回收.一般就是直接New创建的对象. persistent(持久态):已经与当前session产生关联,并且相关联的session没

详解Hibernate中的二级缓存

1.前言 这篇博客再前几篇博客的基础上来讲解一下,Hibernate中的二级缓存,二级缓存是属于SessionFactory级别的缓存机制.第一级别的缓存是Session级别的缓存,是属于事务范围的缓存,由Hibernate管理,一般无需进行干预.第二级别的缓存是SessionFactory级别的缓存,是属于进程范围的缓存. 2.Hibernate二级缓存 1.分类 二级缓存也分为了两种 内置缓存:Hibernate自带的,不可卸载,通常在Hibernate的初始化阶段,Hibernate会把映

详解Hibernate中的事务

1.前言 上一篇博客讲解了Hibernate中的一级缓存,属于Session级别的,这篇博客讲解一下Hibernate中的事务机制.有关事务的概念,请参照通俗易懂数据库中的事务.  2.如何处理Hibernate中的事务 我们知道数据库中的事务,会造成一些影响.比如脏读.不可重复读.幻读.那么如何解决这些问题呢? 1.隔离级别设置 通过设置数据库的隔离级别可以消除一些影响.请参照博客通俗易懂数据库中的事务. 在hibernate中也有四种隔离级别,分别是 1-Read uncommitted i

【Hibernate】详解Hibernate中的inverse=”true”

首先两个类,一个是班级类,一个是学生类: public class Grade{ private int id; private String name; private Set students = new HashSet(); } public class Student { private int id; private String studentName; } 数据库中表的结构: t_grade: 两个字段:id  name t_student: 三个字段:id  studentNam

用IDEA详解Spring中的IoC和DI(挺透彻的,点进来看看吧)

用IDEA详解Spring中的IoC和DI 一.Spring IoC的基本概念 控制反转(IoC)是一个比较抽象的概念,它主要用来消减计算机程序的耦合问题,是Spring框架的核心.依赖注入(DI)是IoC的另外一种说法,只是从不同的角度描述相同的概念.看完这两句,是不是不但没懂,反而更迷惑了,别急,往下看: IoC的背景 我们都知道,在采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑. 如果我们打开机械式手表的后盖,就会看到与

详解Android中那些酷炫返回方式的实现

Android手机都会有返回键,不管是实体键,还是虚拟键.Android用户主要也都是通过这个返回键操控页面返回方式的,不比IOS逼格甚高的只保留一个操作键.这种方式是最普遍的返回方式,还有一种也是比较常见的,那就是页面内部自己响应.绝大多数APP每个页面的设计图顶部左侧都会有一个返回键图标,偶尔也有奇葩的设计放在底部左侧,点击这个图标即finish掉当前页面.简单的介绍完了最常见的两种方式,下面为大家介绍两种更友好的交互方式. 拿大家比较常用的三款社交软件的交互来说.腾讯微博的返回方式除去上述

CSS学习笔记(9)--详解CSS中:nth-child的用法

详解CSS中:nth-child的用法 前端的哥们想必都接触过css中一个神奇的玩意,可以轻松选取你想要的标签并给与修改添加样式,是不是很给力,它就是":nth-child". 下面我将用几个典型的实例来给大家讲解:nth-child的实际用途: Tips:还用低版本的IE浏览器的哥们请绕过! :nth-child(2)选取第几个标签,"2可以是你想要的数字" .demo01 li:nth-child(2){background:#090} :nth-child(n

详解HTTP中get和post的区别

1.详解HTTP中GET和POST的区别 http://www.jellythink.com/archives/806 2.HTTP 方法:GET 对比 POST http://www.cnblogs.com/liu-ke/p/4198815.html