hibernate 通过子查询预抓取集合 fetch subselect join (最后遗留疑问)

(总结在后面) 
通过子查询预抓取集合:
  1. <set fetch="subselect" ..>  
  2.   
  3. @org.hibernate.annotations.Fetch(org.hibernate.annotations.FetchMode.SUBSELECT)  

配置文件:
  1.   <class name="Item" table="ITEM">  
  2.       <id name="itemId" column="ITEM_ID" type="integer">  
  3.           <generator class="native"/>  
  4.       </id>  
  5.       <property name="itemName" type="string" column="ITEM_NAME"/>  
  6.         
  7. <bag name="bids" inverse="true" cascade="save-update" fetch="subselect">  
  8.     <key column="ITEM_ID_M"></key>  
  9.     <one-to-many class="Bid"/>  
  10. </bag>  
  11.           
  12.   </class>  

测试代码:
  1.     private static void select() {  
  2.         Configuration configuration = new Configuration().configure();  
  3.         SessionFactory sessionFactory = configuration.buildSessionFactory();  
  4.         Session session = sessionFactory.openSession();  
  5.           
  6.         Item item = (Item) session.get(Item.class1);  
  7.           
  8.         System.out.println("-----");  
  9.           
  10.         Collection<Bid> bids = item.getBids();  
  11.           
  12.         System.out.println("+++++");  
  13.           
  14.         for(Iterator it = bids.iterator();it.hasNext();){  
  15.             Bid bid = (Bid) it.next();  
  16.             System.out.println(bid);  
  17.         }  
  18.           
  19. //      hibernate打印:  
  20. //      Hibernate: select item0_.ITEM_ID as ITEM1_1_0_, item0_.ITEM_NAME as ITEM2_1_0_ from ITEM item0_ where item0_.ITEM_ID=?  
  21. //      -----  
  22. //      +++++  
  23. //      Hibernate: select bids0_.ITEM_ID_M as ITEM3_1_, bids0_.BID_ID as BID1_1_, bids0_.BID_ID as BID1_0_0_, bids0_.bidMoeny as bidMoeny0_0_, bids0_.ITEM_ID_M as ITEM3_0_0_ from BID bids0_ where bids0_.ITEM_ID_M=?  
  24. //      Bid [bidId=1, bidMoeny=12.0]  
  25. //      Bid [bidId=2, bidMoeny=13.0]  
  26.           
  27.   
  28. //如果是多条就会变成:  
  29. //Hibernate: select bids0_.ITEM_ID_M as ITEM3_1_1_, bids0_.BID_ID as BID1_1_, bids0_.BID_ID as BID1_0_0_, bids0_.bidMoeny as bidMoeny0_0_, bids0_.ITEM_ID_M as ITEM3_0_0_ from BID bids0_ where bids0_.ITEM_ID_M in (select item0_.ITEM_ID from ITEM item0_)  
  30.   
  31.   
  32.         session.close();  
  33.           
  34.         sessionFactory.close();  
  35.     }  






通过联结即时抓取: 
  1. <set fetch="join" ..>  
  2.   
  3. @org.hibernate.annotations.Fetch(org.hibernate.annotations.FetchMode.JOIN)  


配置文件:
  1.   <class name="Item" table="ITEM">  
  2.       <id name="itemId" column="ITEM_ID" type="integer">  
  3.           <generator class="native"/>  
  4.       </id>  
  5.       <property name="itemName" type="string" column="ITEM_NAME"/>  
  6.         
  7. <set name="bids" inverse="true" cascade="save-update" fetch="join">  
  8.     <key column="ITEM_ID_M"></key>  
  9.     <one-to-many class="Bid"/>  
  10. </set>  
  11.           
  12.   </class>  

测试代码: 
很奇怪,不解,难道我这个版本的hibernate有bug?把session.close();放在获取之前就会报no session的错误,那么肯定就是采用的懒加载的方式 
  1.     /** 
  2.      * 前提是我Item有三条数据,两条没有Bid 
  3.      */  
  4.     private static void select() {  
  5.         Configuration configuration = new Configuration().configure();  
  6.         SessionFactory sessionFactory = configuration.buildSessionFactory();  
  7.         Session session = sessionFactory.openSession();  
  8.           
  9.         Query query = session.createQuery("select o from Item o");  
  10.         List<Item> items = query.list();  
  11.           
  12.         System.out.println(items.size());  
  13.           
  14.         for(int i=0;i<items.size();i++){  
  15.             Item item = items.get(i);  
  16.             System.out.println(item.getBids());  
  17.         }  
  18. //      后台打印:  
  19. //      Hibernate: select item0_.ITEM_ID as ITEM1_1_, item0_.ITEM_NAME as ITEM2_1_ from ITEM item0_  
  20. //      3  
  21. //      Hibernate: select bids0_.ITEM_ID_M as ITEM3_1_, bids0_.BID_ID as BID1_1_, bids0_.BID_ID as BID1_0_0_, bids0_.bidMoeny as bidMoeny0_0_, bids0_.ITEM_ID_M as ITEM3_0_0_ from BID bids0_ where bids0_.ITEM_ID_M=?  
  22. //      [Bid [bidId=2, bidMoeny=12.0], Bid [bidId=1, bidMoeny=13.0]]  
  23. //      Hibernate: select bids0_.ITEM_ID_M as ITEM3_1_, bids0_.BID_ID as BID1_1_, bids0_.BID_ID as BID1_0_0_, bids0_.bidMoeny as bidMoeny0_0_, bids0_.ITEM_ID_M as ITEM3_0_0_ from BID bids0_ where bids0_.ITEM_ID_M=?  
  24. //      []  
  25. //      Hibernate: select bids0_.ITEM_ID_M as ITEM3_1_, bids0_.BID_ID as BID1_1_, bids0_.BID_ID as BID1_0_0_, bids0_.bidMoeny as bidMoeny0_0_, bids0_.ITEM_ID_M as ITEM3_0_0_ from BID bids0_ where bids0_.ITEM_ID_M=?  
  26. //      []  
  27.           
  28.           
  29. //      很奇怪,不解,难道我这个版本的hibernate有bug?把session.close();放在获取之前就会报no session的错误,那么肯定就是采用的懒加载的方式  
  30.   
  31.           
  32.           
  33.         session.close();  
  34.           
  35.         sessionFactory.close();  
  36.     }  
  37.       


换个版本(hibernate-distribution-3.6.4.Final): 
还是这样。 
突然明白过来,他在你指定的HQL中,如何生效呢?呵呵 
  1.     /** 
  2.      * 前提是我Item有三条数据,两条没有Bid 
  3.      */  
  4.     private static void select2() {  
  5.         Configuration configuration = new Configuration().configure();  
  6.         SessionFactory sessionFactory = configuration.buildSessionFactory();  
  7.         Session session = sessionFactory.openSession();  
  8.           
  9.         Item item = (Item) session.get(Item.class1);  
  10. //      打印:  
  11. //      Hibernate: select item0_.ITEM_ID as ITEM1_1_1_, item0_.ITEM_NAME as ITEM2_1_1_, bids1_.ITEM_ID_M as ITEM3_1_3_, bids1_.BID_ID as BID1_3_, bids1_.BID_ID as BID1_0_0_, bids1_.bidMoeny as bidMoeny0_0_, bids1_.ITEM_ID_M as ITEM3_0_0_ from ITEM item0_ left outer join BID bids1_ on item0_.ITEM_ID=bids1_.ITEM_ID_M where item0_.ITEM_ID=?  
  12.   
  13.           
  14.         session.close();  
  15.           
  16.         sessionFactory.close();  
  17.     }  
  18.       


JPA:
  1. @Entity  
  2. public class Item implements Serializable {  
  3.     @Id  
  4.     @GeneratedValue  
  5.     @Column(name="ITEM_ID")  
  6.     private Integer itemId;  
  7.     @Column(name="ITEM_NAME")  
  8.     private String itemName;  
  9.       
  10.     @OneToMany(mappedBy="item",cascade=CascadeType.ALL)  
  11.     @Fetch(value=FetchMode.JOIN)  
  12.     private Set<Bid> bids = new HashSet<Bid>();  
  13.   
  14. .....  

调用: 
执行了查询集合数据 
  1.     private static void select() {  
  2.         EntityManagerFactory factory = Persistence.createEntityManagerFactory("partner4java");  
  3.         EntityManager em = factory.createEntityManager();  
  4.           
  5.         Query query = em.createQuery("select o from Item o ");  
  6.         List<Item> items = query.getResultList();  
  7.           
  8. //      后台打印:  
  9. //      Hibernate: select item0_.ITEM_ID as ITEM1_1_, item0_.ITEM_NAME as ITEM2_1_ from Item item0_  
  10. //      Hibernate: select bids0_.ITEM_ID as ITEM3_1_1_, bids0_.BID_ID as BID1_1_, bids0_.BID_ID as BID1_0_0_, bids0_.BID_MONEY as BID2_0_0_, bids0_.ITEM_ID as ITEM3_0_0_ from Bid bids0_ where bids0_.ITEM_ID=?  
  11. //      Hibernate: select bids0_.ITEM_ID as ITEM3_1_1_, bids0_.BID_ID as BID1_1_, bids0_.BID_ID as BID1_0_0_, bids0_.BID_MONEY as BID2_0_0_, bids0_.ITEM_ID as ITEM3_0_0_ from Bid bids0_ where bids0_.ITEM_ID=?  
  12.   
  13.           
  14.         em.close();  
  15.         factory.close();  
  16.     }     
  17.   
  18.       
  19.   
  20.     private static void select2() {  
  21.         EntityManagerFactory factory = Persistence.createEntityManagerFactory("partner4java");  
  22.         EntityManager em = factory.createEntityManager();  
  23.           
  24.         Item item = em.find(Item.class1);  
  25.         System.out.println("----");  
  26.         System.out.println(item.getBids());  
  27.           
  28. //      后台打印:  
  29. //      Hibernate: select item0_.ITEM_ID as ITEM1_0_1_, item0_.ITEM_NAME as ITEM2_0_1_, bids1_.ITEM_ID as ITEM3_0_3_, bids1_.BID_ID as BID1_3_, bids1_.BID_ID as BID1_1_0_, bids1_.BID_MONEY as BID2_1_0_, bids1_.ITEM_ID as ITEM3_1_0_ from Item item0_ left outer join Bid bids1_ on item0_.ITEM_ID=bids1_.ITEM_ID where item0_.ITEM_ID=?  
  30. //      ----  
  31. //      [Bid [bidId=1, bidMoeny=12.0], Bid [bidId=2, bidMoeny=13.0]]  
  32.           
  33.         //但是,我们是三条数据,一条Item没有Bid,所以出问题了  
  34.           
  35.         em.close();  
  36.         factory.close();  
  37.     }  
  38.   
  39.       
  40.   
  41.       


上面这样就生效了。看来fetch方式如此不堪。 
##总结:## 

JPA使用下面代码测试(前提是有三条Item,一条没有Bid数据):
  1. private static void select() {  
  2.     EntityManagerFactory factory = Persistence.createEntityManagerFactory("partner4java");  
  3.     EntityManager em = factory.createEntityManager();  
  4.       
  5.     Query query = em.createQuery("select o from Item o ");  
  6.     List<Item> items = query.getResultList();  
  7.       
  8.     em.close();  
  9.     factory.close();  
  10. }  


join: 
1、无论使用hibernate和jpa使用HQL或者QL语句,是不生效的。 
2、区别在于JPA: 
@OneToMany(mappedBy="item",cascade=CascadeType.ALL,fetch=FetchType.LAZY) 
@Fetch(value=FetchMode.JOIN) 
后台打印: 
Hibernate: select item0_.ITEM_ID as ITEM1_0_, item0_.ITEM_NAME as ITEM2_0_ from Item item0_ 
Hibernate: select bids0_.ITEM_ID as ITEM3_0_1_, bids0_.BID_ID as BID1_1_, bids0_.BID_ID as BID1_1_0_, bids0_.BID_MONEY as BID2_1_0_, bids0_.ITEM_ID as ITEM3_1_0_ from Bid bids0_ where bids0_.ITEM_ID=? 
Hibernate: select bids0_.ITEM_ID as ITEM3_0_1_, bids0_.BID_ID as BID1_1_, bids0_.BID_ID as BID1_1_0_, bids0_.BID_MONEY as BID2_1_0_, bids0_.ITEM_ID as ITEM3_1_0_ from Bid bids0_ where bids0_.ITEM_ID=? 
Hibernate: select bids0_.ITEM_ID as ITEM3_0_1_, bids0_.BID_ID as BID1_1_, bids0_.BID_ID as BID1_1_0_, bids0_.BID_MONEY as BID2_1_0_, bids0_.ITEM_ID as ITEM3_1_0_ from Bid bids0_ where bids0_.ITEM_ID=? 
像这样,无论,JPA中你是否指明了懒加载,只要生命了fetch=join方式,就会变成立即加载。 

Hibernate不会,hibernate始终就是默认就是把返回代理放在最优先考虑的方式。 
3、如果使用非HQL或QL的查询方式,如get之类的,JOIN就会出现问题,因为使用的left outer join方式,就只会查询出有关联数据的Item。 


SUBSELECT: 
1、JPA和hibernate是相同的: 
@OneToMany(mappedBy="item",cascade=CascadeType.ALL,fetch=FetchType.LAZY) 
@Fetch(value=FetchMode.SUBSELECT) 
就是,默认是懒加载模式 
后台打印: 
Hibernate: select item0_.ITEM_ID as ITEM1_1_, item0_.ITEM_NAME as ITEM2_1_ from Item item0_ 

2、但是,如果修改为: 
@OneToMany(mappedBy="item",cascade=CascadeType.ALL,fetch=FetchType.EAGER) 
@Fetch(value=FetchMode.SUBSELECT) 
后台就会打印: 
Hibernate: select item0_.ITEM_ID as ITEM1_1_, item0_.ITEM_NAME as ITEM2_1_ from Item item0_ 
Hibernate: select bids0_.ITEM_ID as ITEM3_1_1_, bids0_.BID_ID as BID1_1_, bids0_.BID_ID as BID1_0_0_, bids0_.BID_MONEY as BID2_0_0_, bids0_.ITEM_ID as ITEM3_0_0_ from Bid bids0_ where bids0_.ITEM_ID in (select item0_.ITEM_ID from Item item0_) 
就是JPA中QL语句也会生效SUBSELECT设置。Hibernate也会生效。



所以,综上所述,当时使用HQL或QL查询的时候,而且需要获取脱管对象的关联对象时,建议使用SUBSELECT方式,但是,还需要额外指明即时加载。且,JPA的JOIN方式的QL查询还存在bug。 



但是,我们如果想在第一个select的HQL方式中也用join该如何呢? 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值