Hibernate延迟加载简单实例及分析

	Session session = HibernateUtil.openSession();

		Transaction tx = null;

		tx = session.beginTransaction();
		
		User user=(User) session.get(User.class, 538);
	 
		System.out.println(user.getId());
	   
		tx.commit();
		
		session.close();
		
		
		System.out.println(user.getName());


Hibernate在使用get方法时,当程序运行到
User user=(User) session.get(User.class, 538);
就会直接提取出User对象,也就是向数据库发送了select语句。

get方法直接获取实例, 不存在代理。

------------------
这时如果把get换成load, 就会报出一个经典的异常。
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:164)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:285)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185)
at com.lj.zhang.User_$$_javassist_0.getName(User_$$_javassist_0.java)
at com.lj.zhang.HibernateTest5_search2.main(HibernateTest5_search2.java:47)


从上面的异常信息可以看出, hibernate通过javassist生成的代理对象进行了invoke()的调用, 我猜测应该就是这里调用了javassist所生成的对象类的查询方法。
这个生成的对象class的查询方法在运行时是要通过hibernate的一系列的配置对象的,既是SessionImpl, 但是这个东西已经关闭, 所以getImplementation压根无法得到任何Session对象。 抛出异常。
--以上纯属瞎猜,具体如何还待以后看了源码才知道。




=========================分割线===============
在mapping配置文件中, 我们可以取消延迟加载 , 通过lazy=false。
  <hibernate-mapping package="com.lj.zhang">
  <class name="User" table="test_user" lazy="false">
当配置了lazy=false之后, 这个User对象便会在session.load()被执行时直接被实例化。 (select语句也会被执行)



		tx.commit();
		
		session.close();
		
		
		System.out.println(user.getName());
		System.out.println(user.getOrders().iterator().next().getName());

于是user.getName()会被正常执行。

这里要注意的就是第二个System.out.println会报错。


Exception in thread "main" org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.lj.zhang.User.orders, could not initialize proxy - no Session
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:566)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:186)
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:545)
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:124)
at org.hibernate.collection.internal.PersistentSet.iterator(PersistentSet.java:180)
at com.lj.zhang.HibernateTest5_search2.main(HibernateTest5_search2.java:48)



这个错误我会想当然的认为, Order配置文件里只要也设置lazy=false,问题就会解决。
事实是这个想法很2,
在Order里面设置这个没有任何作用。
因为Order在main程序中并不是通过load获取的, 而是通过级联获取。

所以重点在一对多的主键那里的配置。也就是User.hbm.xml里面的

<set name="orders" cascade="save-update" inverse="true"   >    <!-- 级联, inverse=true表示由多的一方维持关联关系 -->
  				<!-- key的column告诉hibernate多的一方的foreign key -->
  				<!--  这里设置为customer_id, 就会在数据库的order表里生成相应的 -->
  				<key column="customer_id"></key>
  				<one-to-many class="com.lj.zhang.Order"/>
  			</set>


在set节点里加入 lazy="false",
问题就解决了。

此时通过debug模式可以看到, 程序在运行到
User user=(User) session.load(User.class, 538);
的时候, 便会向数据库发送两条select查询语句。
Hibernate: select user0_.id as id1_2_0_, user0_.test_name as test2_2_0_, user0_.test_age as test3_2_0_ from test_user user0_ where user0_.id=?

Hibernate: select orders0_.customer_id as customer3_2_1_, orders0_.id as id1_0_1_, orders0_.id as id1_0_0_, orders0_.test_name as test2_0_0_, orders0_.customer_id as customer3_0_0_ from test_order orders0_ where orders0_.customer_id=?

这时User以及与之关联的Order对象便有了。 程序正常运行。

猜你喜欢

转载自alleni123.iteye.com/blog/1976001
今日推荐