關於Hiberante FetchMode

以Person, Address 爲例, 其關係爲一對多,數據庫中有3條person, 每個分別對應2條address。查詢語句如下: 

Java代碼  收藏代碼
  1. Criteria c = session.createCriteria(Person.class);  
  2. c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);  
  3. List<Person> list = (List<Person>)c.list();  
  4. for (Person p : list) {  
  5.         System.out.println(p.getName());  
  6.               
  7.     Set<Address> addressSet = p.getAddressSet();  
  8.     for (Address a : addressSet) {  
  9.         System.out.println(a);  
  10.     }             
  11. }  


1 默認不設置FetchMode 
Java代碼  收藏代碼
  1. @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)  
  2. @JoinColumn(name = "P_ID")  
  3. public Set<Address> getAddressSet() {  
  4.     return addressSet;  
  5. }  


結果生成如下 
Java代碼  收藏代碼
  1. Hibernate: select this_.PERSON_ID as PERSON1_0_0_, this_.PERSON_NAME as PERSON2_0_0_   
  2. from PERSON this_  
  3. P1  
  4. Hibernate: select addressset0_.P_ID as P3_1_, addressset0_.ADDRESS_ID as ADDRESS1_1_, addressset0_.ADDRESS_ID as ADDRESS1_1_0_, addressset0_.ADDRESS_NAME as ADDRESS2_1_0_   
  5. from ADDRESS addressset0_   
  6. where addressset0_.P_ID=?  
  7. 2   P1 A2  
  8. 1   P1 A1  
  9. P2  
  10. Hibernate: select addressset0_.P_ID as P3_1_, addressset0_.ADDRESS_ID as ADDRESS1_1_, addressset0_.ADDRESS_ID as ADDRESS1_1_0_, addressset0_.ADDRESS_NAME as ADDRESS2_1_0_   
  11. from ADDRESS addressset0_   
  12. where addressset0_.P_ID=?  
  13. 4   P2 A2  
  14. 3   P2 A1  
  15. P3  
  16. Hibernate: select addressset0_.P_ID as P3_1_, addressset0_.ADDRESS_ID as ADDRESS1_1_, addressset0_.ADDRESS_ID as ADDRESS1_1_0_, addressset0_.ADDRESS_NAME as ADDRESS2_1_0_   
  17. from ADDRESS addressset0_   
  18. where addressset0_.P_ID=?  
  19. 5   P3 A1  
  20. 6   P3 A2  


即:先查所有Person的id, 然後根據id查對應的Address。產生N+1問題 

2. FetchMode.SELECT 

Java代碼  收藏代碼
  1. @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)  
  2. @Fetch(FetchMode.SELECT)  
  3. @JoinColumn(name = "P_ID")  
  4. public Set<Address> getAddressSet() {  
  5.     return addressSet;  
  6. }  

效果同默認,即hibernate默認的FetchMode是SELECT 

3. FetchMode.JOIN 
Java代碼  收藏代碼
  1. @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)  
  2. @Fetch(FetchMode.JOIN)  
  3. @JoinColumn(name = "P_ID")  
  4. public Set<Address> getAddressSet() {  
  5.     return addressSet;  
  6. }  

效果如下 
Java代碼  收藏代碼
  1. Hibernate: select this_.PERSON_ID as PERSON1_0_1_, this_.PERSON_NAME as PERSON2_0_1_, addressset2_.P_ID as P3_3_, addressset2_.ADDRESS_ID as ADDRESS1_3_, addressset2_.ADDRESS_ID as ADDRESS1_1_0_, addressset2_.ADDRESS_NAME as ADDRESS2_1_0_   
  2. from PERSON this_   
  3.    left outer join ADDRESS addressset2_   
  4.         on this_.PERSON_ID=addressset2_.P_ID  
  5.   
  6. P1  
  7. 2   P1 A2  
  8. 1   P1 A1  
  9. P2  
  10. 4   P2 A2  
  11. 3   P2 A1  
  12. P3  
  13. 5   P3 A1  
  14. 6   P3 A2  


採用外聯,用一條sql取出person及其address 

4. FetchMode.SUBSELECT 
Java代碼  收藏代碼
  1. @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)  
  2. @Fetch(FetchMode.SUBSELECT)  
  3. @JoinColumn(name = "P_ID")  
  4. public Set<Address> getAddressSet() {  
  5.     return addressSet;  
  6. }  


效果 
Java代碼  收藏代碼
  1. Hibernate: select this_.PERSON_ID as PERSON1_0_0_, this_.PERSON_NAME as PERSON2_0_0_   
  2. from PERSON this_  
  3. P1  
  4. Hibernate: select addressset0_.P_ID as P3_1_, addressset0_.ADDRESS_ID as ADDRESS1_1_, addressset0_.ADDRESS_ID as ADDRESS1_1_0_, addressset0_.ADDRESS_NAME as ADDRESS2_1_0_   
  5. from ADDRESS addressset0_   
  6. where addressset0_.P_ID in (select this_.PERSON_ID from PERSON this_)  
  7. 2   P1 A2  
  8. 1   P1 A1  
  9. P2  
  10. 4   P2 A2  
  11. 3   P2 A1  
  12. P3  
  13. 6   P3 A2  
  14. 5   P3 A1  

生成2條sql, 第二句用in 查關聯Address數據 


5. batchSize 
Java代碼  收藏代碼
  1. @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)  
  2. @BatchSize(size=4)  
  3. @JoinColumn(name = "P_ID")  
  4. public Set<Address> getAddressSet() {  
  5.     return addressSet;  
  6. }  

效果 
Java代碼  收藏代碼
  1. Hibernate: select this_.PERSON_ID as PERSON1_0_0_, this_.PERSON_NAME as PERSON2_0_0_   
  2. from PERSON this_  
  3. P1  
  4. Hibernate: select addressset0_.P_ID as P3_1_, addressset0_.ADDRESS_ID as ADDRESS1_1_, addressset0_.ADDRESS_ID as ADDRESS1_1_0_, addressset0_.ADDRESS_NAME as ADDRESS2_1_0_   
  5. from ADDRESS addressset0_   
  6. where addressset0_.P_ID in (?, ?, ?)  
  7. 1   P1 A1  
  8. 2   P1 A2  
  9. P2  
  10. 4   P2 A2  
  11. 3   P2 A1  
  12. P3  
  13. 5   P3 A1  
  14. 6   P3 A2  

生成2條sql,第二條用in。 這裏數據庫中共有3條person。 
如果設size=0或1, 則效果同select一樣,產生N+1問題。 
如size=2, 生成3條sql,第一條相同,第二條爲 
Java代碼  收藏代碼
  1. select 。。。。  
  2. from ADDRESS addressset0_   
  3. where addressset0_.P_ID in (?, ?)  

第三條爲 
Java代碼  收藏代碼
  1. select。。  
  2. from ADDRESS addressset0_   
  3. where addressset0_.P_ID=?  


如果設size=3則生成2條sql,第一條相同,第一條爲 
Java代碼  收藏代碼
  1. select 。。。。  
  2. from ADDRESS addressset0_   
  3. where addressset0_.P_ID in (?, ?, ?)  

由上,size即爲in中數據個數。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章