详解Hibernate中的NoSession问题

 

 1.前言

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

详解Hibernate中的NoSession问题_第1张图片


根据字面上的意思,应该是代理不能被初始化,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,但是只有确定了该业务不需要延迟加载的时候,才考虑这种设计。这是一种解决的办法,但是有点死板,把这么好的延迟加载的特性给活生生的去除了。





 
  
   
  
  
 



3.方法二

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


openSessionInView
org.springframework.orm.hibernate3.support.OpenSessionInViewFilter


openSessionInView
/*


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




你可能感兴趣的:(Java学习)