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

实则这个异常写的十分之明白,便是对话封闭,没法对Hibernate实业开展操作。促成这么的景况有很多,什么书写差错啊,逻辑差错啊,之类.不过,偶是由于LAZY.

至于lazy机制:

推迟初始化差错是施用Hibernate开发项目时最常见的差错。如其对一个种也许聚合配备了推迟检索谋略,那么务必现代理类范例或署理聚合居于持久化状态(即居于Session范围内)时,才华初始化它。如果在游离状态时才初始化它,就会发生推迟初始化错处。

下头把Customer.hbm.xml资料的元素的lazy属性设为true,示意施用推迟检索谋略:



应施行Session的load()步骤时,Hibernate不会马上实施查询CUSTOMERS表的select话语,单单回到Customer种的署理种的范例,这个署理类具由以次特点:

(一) 由Hibernate在运行时动态生成,它扩张了Customer种,因而它承袭了Customer种的全部属性和步骤,但它的兑现关于应用程序是透明的。
(二) 应Hibernate创造Customer署理类范例时,单单初始化了它的OID属性,其余属性都为null,因而这个署理类范例占用的内存储器很少。
(三)当应用程序第一回访问Customer署理类范例时(比如调用customer.getXXX()或customer.setXXX()步骤), Hibernate能初始化署理类范例,在初始化过程中实施select话语,真个从数据库中加载Customer对象的全部数据。但有个例外,那就是当应用程序访问Customer署理类范例的getId()步骤时,Hibernate不会初始化署理类范例,由于在创办署理类范例时OID便存在了,毋庸到数据库中去查询。

揭示:Hibernate采取CGLIB工具来世成持久化类的署理种。CGLIB是一个功能强大的Java字节码生成工具,它能够在程序运行时动态生成扩张 Java种可能兑现Java接口的署理种。至于CGLIB的更多学识,请参照:http://cglib.sourceforge.net/。

以次代码先经过Session的load()步骤加载Customer对象,其后访问它的name属性:

tx = session.beginTransaction();
Customer customer=(Customer)session.load(Customer.class,new Long(一));
customer.getName();
tx.commit();

在运作session.load()步骤时Hibernate不施行任何select话语,单单回来Customer种的署理种的范例,它的OID为一,这是由load()步骤的第二个参数指定的。当应用程序调用customer.getName()步骤时,Hibernate能初始化Customer署理类范例,从数据库中加载Customer对象的数据,实施以次select话语:

select * from CUSTOMERS where ID=一;
select * from ORDERS where CUSTOMER_ID=一;

应元素的lazy属性为true,能影响Session的load()步骤的各种运行时举动,下头举例说明。

一.如若加载的Customer对象在数据库中不存在,Session的load()步骤不会抛出异常,唯有当运作customer.getName()步骤时才会抛出以次异常:

ERROR LazyInitializer:63 - Exception initializing proxy
net.sf.hibernate.ObjectNotFoundException: No row with the given identifier exists: 一, of class:
mypack.Customer

二.如果在整个Session范围内,应用程序没访问过Customer对象,那么Customer署理种的范例一直不会被初始化,Hibernate不会实施任何select话语。以次代码意欲在封锁Session后访问Customer游离对象:

tx = session.beginTransaction();
Customer customer=(Customer)session.load(Customer.class,new Long(一));
tx.commit();
session.close();
customer.getName();

因为摘引变量customer引述的Customer署理种的范例在Session范围内始终没被初始化,因此在施行customer.getName()步骤时,Hibernate能抛出以次异常:

ERROR LazyInitializer:63 - Exception initializing proxy
net.sf.hibernate.HibernateException: Could not initialize proxy - the owning Session was closed

有鉴于此,Customer署理种的范例唯有在现阶段Session范围内才干被初始化。

三.net.sf.hibernate.Hibernate种的initialize()静态步骤用以在Session范围内显式初始化署理类范例,isInitialized()步骤用来判断署理类范例是不是已经被初始化。比如:

tx = session.beginTransaction();
Customer customer=(Customer)session.load(Customer.class,new Long(一));
if(!Hibernate.isInitialized(customer))
Hibernate.initialize(customer);
tx.commit();
session.close();
customer.getName();

之上代码在Session范围内透过Hibernate种的initialize()步骤显式初始化了Customer署理类范例,因而应Session封锁后,可以通常访问Customer游离对象。

四.当应用程序访问署理类范例的getId()步骤时,不会触发Hibernate初始化署理类范例的举动,比如:

tx = session.beginTransaction();
Customer customer=(Customer)session.load(Customer.class,new Long(一));
customer.getId();
tx.commit();
session.close();
customer.getName();

当应用程序访问customer.getId()步骤时,该步骤直接回来Customer署理类范例的OID值,毋庸查询数据库。因为引述变量 customer始终摘引的是没被初始化的Customer署理类范例,因而应Session封锁后再施行customer.getName()步骤, Hibernate能抛出以次异常:

ERROR LazyInitializer:63 - Exception initializing proxy
net.sf.hibernate.HibernateException: Could not initialize proxy - the owning Session was closed


解决方法:

因为hibernate采取了lazy=true,这么当你用hibernate查询时,回来现实为利用cglib加强的署理种,但其并没有现实填充;当你在前端,利用它来取值(getXXX)时,这时候Hibernate才会到数据库施行查询,并填充对象,但此刻如若和这个署理类有关的session已封闭掉,就会发生种差错.
在做一对多时,有时会出现"could not initialize proxy - clothe owning Session was sed,这个好像是hibernate的缓存问题.问题解决:急需在里设立lazy="false". 但有可能会挑动另一个异常叫

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

此异常解决方案请观察本人博客(http://hi.baidu.com/kekemao一)的Hibernate异常中的《failed to lazily initialize a collection of role异常》

?
解决方法:在web.xml中加入

hibernateFilter

org.springframework.orm.hibernate三.support.OpenSessionInViewFilter


hibernateFilter
*.do

就可以了;

参照了:
Hibernate与推迟加载:

Hibernate对象关系照射提供推延的与非推延的对象初始化。非推迟加载在读取一个对象的时分会将与这个对象全部相干的其余对象一行读取出来。这有时会以致成百的(如若不是成千的话)select话语在读取对象的时分施行。这个问题有时候出现在施用双向关系的时分,常常会招致整个数据库都在初始化的阶段被读出来了。当然,你可以苦口婆心地检察每一个对象与其说他对象的关系,并把那些最昂贵的剔除,但是到最后,我们可能会因而失去了本想在ORM工具中取得的方便。


一个显然的解决方法是运用Hibernate提供的推延加载机制。这种初始化谋略只在一个对象调用它的一对多或多对多关系时才将关系对象读取出来。这个历程对开发者来说是透明的,并且只进行了很少的数据库操作请求,因此会失去比较显然的性能提拔。这项技术的一个缺陷是推迟加载技术要求一个Hibernate对话要在对象运用的时分一直开着。这会变成透过运用DAO形式将持久层抽象出来时的一个重要问题。为了将持久化机制完全地抽象出来,全部的数据库逻辑,包括打开或封闭对话,都不能在运用层出现。最常见的是,一些兑现了简略接口的DAO兑现类将数据库逻辑完全打包起来了。一种高速但是拙笨的解决方法是抛却DAO形式,将数据库联接逻辑加到运用层中来。这或者对一些小的应用程序有效,但是在大的系统中,这是一个惊人的设计缺陷,妨碍了系统的可扩展性。

在Web层开展推延加载

幸运的是,Spring构架为Hibernate推延加载与DAO方式的调整提供了一种便利的解决方法。对那些不熟悉Spring与Hibernate集成应用的人,我不会在这里议论过剩的细节,但是我提议你去理解Hibernate与Spring集成的数据访问。以一个Web使用为例,Spring提供了OpenSessionInViewFilter和OpenSessionInViewInterceptor。我们可以随便取舍一个种来兑现雷同的效能。两种步骤独一的不同就在于interceptor在Spring器皿中运作并被配备在web使用的前后文中,而Filter在Spring先期运作并被配备在web.xml中。不管用哪个,他们都在请求将目前对话与现阶段(数据库)线程绑定时打开Hibernate对话。万一已绑定到线程,这个打开了的Hibernate对话可以在DAO兑现类中透明地施用。这个对话会为推延加载数据库中值对象的视图护持打开状态。万一这个逻辑视图完成了,Hibernate对话会在Filter的doFilter步骤可能Interceptor的postHandle步骤中被封闭。下部是每个组件的配备示范:



Interceptor的配备:



class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">









class="org.springframework.orm.hibernate.support.OpenSessionInViewInterceptor">




Filter的配备





hibernateFilter

org.springframework.orm.hibernate.support.OpenSessionInViewFilter




hibernateFilter
*. spring





兑现Hibernate的Dao接口来施用打开的对话是很简略的。实际上,如其你已经应用了Spring构架来兑现你的Hibernate Dao,很可能你不需要改变任何东西。便利的HibernateTemplate公用组件使访问数据库成为小菜一碟,而DAO接口唯有透过这个组件才可以访问到数据库。下部是一个示范的DAO:


public class HibernateProductDAO extends HibernateDaoSupport implements ProductDAO {

public Product getProduct(Integer productId) {
return (Product)getHibernateTemplate().load(Product.class, productId);
}

public Integer saveProduct(Product product) {
return (Integer) getHibernateTemplate().save(product);
}

public void updateProduct(Product product) {
getHibernateTemplate().update(product);
}
}


从业务逻辑层中运用推迟加载

即或在视图外边,Spring构架也经过应用AOP 阻截器 HibernateInterceptor来使得推延加载变得很简单兑现。这个Hibernate 阻截器透明地将调用配备在Spring应用程序前后文中的业务对象中步骤的请求阻截下来,在调用步骤头里打开一个Hibernate对话,其后在步骤实施完以后将对话封锁。让我们来看一个容易的事例,假想我们有一个接口BussinessObject:


public interface BusinessObject {
public void doSomethingThatInvolvesDaos();
}
种BusinessObjectImpl兑现了BusinessObject接口:

public class BusinessObjectImpl implements BusinessObject {
public void doSomethingThatInvolvesDaos() {
// lots of logic that calls
// DAO classes Which access
// data objects lazily
}
}



透过在Spring应用程序前后文中的一些配备,我们可以让将调用BusinessObject的步骤阻截下来,再令它的步骤支持推迟加载。见见下部的一个程序片断:















com.acompany.BusinessObject



hibernateInterceptor





应businessObject被调用的时分,HibernateInterceptor打开一个Hibernate对话,并将调用请求传送给BusinessObjectImpl对象。应BusinessObjectImpl施行完成后,HibernateInterceptor透明地封闭了对话。使用层的代码不要懂得任何持久层逻辑,仍是兑现了推迟加载。


在单元测试中测试推迟加载

最后,我们急需用J-Unit来测试我们的推延加载程序。我们可以轻易地透过重写TestCase种中的setUp和tearDown步骤来兑现这个要求。我比较喜爱用这个便利的抽象类作为我全部测试种的基类。


public abstract class MyLazyTestCase extends TestCase {

private SessionFactory sessionFactory;
private Session session;

public void setUp() throws Exception {
super.setUp();
SessionFactory sessionFactory = (SessionFactory) getBean("sessionFactory");
session = SessionFactoryUtils.getSession(sessionFactory, true);
Session s = sessionFactory.openSession();
TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(s));

}

protected Object getBean(String beanName) {
//Code to get objects from Spring application context
}

public void tearDown() throws Exception {
super.tearDown();
SessionHolder holder = (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
Session s = holder.getSession();
s.flush();
TransactionSynchronizationManager.unbindResource(sessionFactory);
SessionFactoryUtils.closeSessionIfNecessary(s, sessionFactory);
}
本文来源:
我的异常网
Java Exception
Dotnet Exception
Oracle Exception

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值