外连接对预先抓取的影响

只要在HQL中指定了外连接,那么不论配置文件中是预先抓取或是立即或延迟检索,都会失效。

 

以上面为例:

学生对身份证采取预先抓取和立即检索,对班级是预先抓取,班级对学生是延迟加载。

 

Session session = SessionUtil.getSession();
  Transaction tran = session.beginTransaction();
  Query query = session.createQuery("from Student as s left join s.teamID");
  List list = query.list();
  tran.commit();
  session.close();
  Object st[] = (Object[])list.get(0);
  Student s = (Student) st[0];
  System.out.println(s.getName());
  System.out.println(s.getTeamID().getName());
  System.out.println(s.getTeamID().getStudents().size());

 

在查询的LIST中包含两个长度为2的数组,每一个数组包含两个对象,学生对象和班级对象。

打印:

1.Hibernate: select student0_.ID as ID1_0_, team1_.ID as ID0_1_, student0_.Name as Name1_0_, student0_.TeamID as TeamID1_0_, team1_.Name as Name0_1_ from test.student student0_ left outer join test.team team1_ on student0_.TeamID=team1_.ID

2.Hibernate: select card0_.ID as ID2_0_, card0_.StudentID as StudentID2_0_, card0_.Name as Name2_0_ from test.card card0_ where card0_.ID=?

3.Hibernate: select card0_.ID as ID2_0_, card0_.StudentID as StudentID2_0_, card0_.Name as Name2_0_ from test.card card0_ where card0_.ID=?
tuping
Exception in thread "main" org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.vo.Team.students, no session or session was closed
 at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:358)
 at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:350)
 at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:97)
 at org.hibernate.collection.PersistentSet.size(PersistentSet.java:139)
 at com.test.Client1.main(Client1.java:28)
二中

 

对1的解释:因为采取的是HQL中的左连接的方式,所以会忽略配置中预先抓取的方式。

对2.3的解释:在配置文件中的检索策略只能影响到session.get()或load方法,对于直接使用HQL的方式将忽略配置文件的预先抓取的检索策略,而是直接采取HQL中的方式。

1)得到学生对象以后,学生对身份证的预先抓取策略失效,二是采取的是立即加载得到身份证。

2)得到班级对象以后,由于班级对学生采用了延迟加载(这个策略将不会忽略),于是班级的学生集合并没有得到初始化。所以才打印出例外。

 

将班级对学生的加载方式改为立即加载就OK了。

 

打印:

1.Hibernate: select student0_.ID as ID1_0_, team1_.ID as ID0_1_, student0_.Name as Name1_0_, student0_.TeamID as TeamID1_0_, team1_.Name as Name0_1_ from test.student student0_ left outer join test.team team1_ on student0_.TeamID=team1_.ID
2.Hibernate: select card0_.ID as ID2_0_, card0_.StudentID as StudentID2_0_, card0_.Name as Name2_0_ from test.card card0_ where card0_.ID=?
3.Hibernate: select card0_.ID as ID2_0_, card0_.StudentID as StudentID2_0_, card0_.Name as Name2_0_ from test.card card0_ where card0_.ID=?

4.Hibernate: select students0_.teamID as teamID3_, students0_.ID as ID3_, students0_.ID as ID1_2_, students0_.Name as Name1_2_, students0_.TeamID as TeamID1_2_, team1_.ID as ID0_0_, team1_.Name as Name0_0_, card2_.ID as ID2_1_, card2_.StudentID as StudentID2_1_, card2_.Name as Name2_1_ from test.student students0_ left outer join test.team team1_ on students0_.TeamID=team1_.ID left outer join test.card card2_ on students0_.ID=card2_.ID where students0_.teamID=?
tuping
二中
2

 

这里有个疑问,因为第2.3已经得到了CARD的对象,为什么第4句还要去数据库取一次数据。这是因为第一次发送SQL语句从数据库取身份证对象时,学生对身份证采取的是预先抓取被忽略,所以采取了立即加载的策略。

而班级对学生采用HQL指定的左连接取得对象。

虽然班级和学生对象都取得了。但是由于集合的特殊性,还需要取得集合对学生对象的引用。由于学生对身份证采取的是预先抓取,所有才会有第4句。

 

 

如果在语句中改用Fetch进行连接

Session session = SessionUtil.getSession();
  Transaction tran = session.beginTransaction();
  Query query = session.createQuery("from Student as s left join fetch s.teamID");
  List list = query.list();
  tran.commit();
  session.close();
 // Object st[] = (Object[])list.get(0);这种得到对象的方式就是错的。
  //Student s = (Student) st[0];

 

//通过查询虽然与上面生成的SQL语句是一样的,但是再内存中得到的对象却发生了变化。此时检索出来的是两个学生元素。所以通过LIST得到的集合是学生的集合。


  Student s = (Student) list.get(0);
  System.out.println(s.getName());
  System.out.println(s.getTeamID().getName());
  System.out.println(s.getTeamID().getStudents().size());

 

HQL忽略配置文件预先抓取的深度。

如果HQL语句中出现了外连接from Team t left outer join t.students

则班级对学生的预先抓取的策略将被HQL指定的左外连接所覆盖。

 

举例:

学生对身份证采取预先抓取和立即加载,学生对班级采取预先抓取,班级对学生采取预先抓取和延迟检索。

通过查寻得到的结果是学生对身份证的预先抓取也被忽略了。HQL忽略配置文件预先抓取策略深度就是HQL语句中指定的对象,HIBERNATE对这些对象直接的属性配置忽略预先抓取,采取立即或延迟检索的策略。假设身份证还关联其他对象,则这些对象的抓取策略按照配置文件的设定,预先抓取不会被忽略。

 

 

 

总结:

1.仅仅从使用角度来看,预先抓取和立即检索的效果一样,只不过预先抓取可以减少SQL语句条数。

2.预先抓取的关键字是JOIN和FETCH,而外连接的关键字是JOIN

3.预先抓取将初始化代理对象的引用,吧对象的数据填充完毕,但是外连接只是把对象组装好,不会初始化对象之间的引用关系。

 

你可能感兴趣的:(thread,sql,Hibernate)