延迟初始化错误是运用hibernate开发项目时最常见的错误。如果对一个类或者集合配置了延迟检索策略,那么必须当代理类实例或代理集合处于持久化状态(即处于session范围内)时,才能初始化它。如果在游离状态时才初始化它,就会产生延迟初始化错误。
下面把customer.hbm.xml文件的
当执行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的更多知识,请参考:http://cglib.sourceforge.net/。
以下代码先通过session的load()方法加载customer对象,然后访问它的name属性:
tx = session.begintransaction();
customer customer=(customer)session.load(customer.class,new long(1));
customer.getname();
tx.commit();
在 运行session.load()方法时hibernate不执行任何select语句,仅仅返回customer类的代理类的实例,它的oid为1,这 是由load()方法的第二个参数指定的。当应用程序调用customer.getname()方法时,hibernate会初始化customer代理 类实例,从数据库中加载customer对象的数据,执行以下select语句:
select * from customers where id=1;
select * from orders where customer_id=1;
当
1.如果加载的customer对象在数据库中不存在,session的load()方法不会抛出异常,只有当运行customer.getname()方法时才会抛出以下异常:
error lazyinitializer:63 - exception initializing proxy
net.sf.hibernate.objectnotfoundexception: no row with the given identifier exists: 1, of class:
mypack.customer
2.如果在整个session范围内,应用程序没有访问过customer对象,那么customer代理类的实例一直不会被初始化,hibernate不会执行任何select语句。以下代码试图在关闭session后访问customer游离对象:
tx = session.begintransaction();
customer customer=(customer)session.load(customer.class,new long(1));
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范围内才能被初始化。
3.net.sf.hibernate.hibernate类的initialize()静态方法用于在session范围内显式初始化代理类实例,isinitialized()方法用于判断代理类实例是否已经被初始化。例如:
tx = session.begintransaction();
customer customer=(customer)session.load(customer.class,new long(1));
if(!hibernate.isinitialized(customer))
hibernate.initialize(customer);
tx.commit();
session.close();
customer.getname();
以上代码在session范围内通过hibernate类的initialize()方法显式初始化了customer代理类实例,因此当session关闭后,可以正常访问customer游离对象。
4.当应用程序访问代理类实例的getid()方法时,不会触发hibernate初始化代理类实例的行为,例如:
tx = session.begintransaction();
customer customer=(customer)session.load(customer.class,new long(1));
customer.getid();
tx.commit();
session.close();
customer.getname();
当 应用程序访问customer.getid()方法时,该方法直接返回customer代理类实例的oid值,无需查询数据库。由于引用变量 customer始终引用的是没有被初始化的customer代理类实例,因此当session关闭后再执行customer.getname()方法, hibernate会抛出以下异常:
error lazyinitializer:63 - exception initializing proxytrackback: http://tb.blog.csdn.net/trackback.aspx?postid=656003