2012-10-31 88 views
4

在我的web應用程序中,我有一個與Child具有OneToMany關係的對象。 當選擇我的對象我執行以下查詢:jpa兒童體型表現

from Object o 

,然後我應打印的每個對象有多少孩子有

// Foreach 
object.children.size() 

假設對象有很多孩子(讓我們說30'000); 是否浪費資源調用size()或者ORM框架(在我的情況下是Hibernate)會在不加載所有子項的情況下處理這個問題?

回答

3

使用JPA(標準):

  • 你@OneToMany關係是默認的延遲加載(即fetch = FetchType.LAZY的默認值)。但是調用Entity.getCollection().size()會觸發延遲加載來檢索所有的子集合 - 所以是的,它會相當緩慢,除非您需要對所有/大多數元素進行操作。注意:對於JPA的所有(理性)實現,這不會發出30,000個單獨的查詢 - 它將發出一個查詢,返回結果集中的30,000行。
  • 如果你最需要的元素,或者您想提前變化緩存到@OneToMany(fetch=FetchType.EAGER)
  • 的常用方法就獲得的數據統計而無需檢索每一個目標很簡單,就是(通過getNativeQUery()甚至SQL)通過EntityManager.getQuery()/getTypedQuery()/getNamedQuery()使用JPQL。這是非常簡單,具有高性能:
int empSize = em.createQuery("SELECT SIZE(d.employees) FROM Department d")  
       .getSingleResult();  
OR ALTERNATIVELY 

// Pre-compiled query placed against entity class for highest performance 
@NamedQueries({ 
    @NamedQuery(name="Department.EmployeeSize", 
       query="SELECT SIZE(d.employees) FROM Department"), 
    ... // other named queries 
}) 
@Entity 
public class Department { 

    ... 

} 

// Then to use the query:  
int empSize = em.createNamedQuery("Department.EmployeeSize", Integer.class)  
       .getSingleResult();  
Map propertiesMap = new HashMap(); 
// Valid values are ALL, NONE, ENABLE_SELECTIVE, DISABLE_SELECTIVE 
propertiesMap.add("javax.persistence.sharedCache.mode", "ENABLE_SELECTIVE"); 
EntityManagerFactory = Persistence.createEntityManagerFactory("myPUName", propertiesMap); 
ALTERNATIVELY use persistence.xml: 

<persistence-unit name="EmployeeService"> 
    ... 
    <shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode> 

</persistence-unit> 

然後標記哪些實體應在2級緩存自動緩存:

@Cacheable(true) 
@Entity 
public class Employee { 
    ... 
} 
  • 還可以動態配置緩存,作爲一個特定的查詢

使用專有方法的一部分(例如休眠 「超懶」 的集合):

  • 相同的性能,簡單地發出JPQL/SQL查詢
  • 節省幾行代碼(@ org.hibernate.annotations.LazyCollection(EXTRA)註釋訴@ NamedQuery註釋和執行)
  • 不標準 - JPA培訓的開發人員不會知道它
  • 不可移植 - 只能與該供應商一起使用。標準JPA有一種行業趨勢,遠離專有特性。在那裏有許多不同的JPA實現。
2

在您的JPA實現中啓用日誌消息並查看真正發送到數據庫的數據庫查詢是個好主意。在你的情況下,我會說ORM可能會懶惰地加載所有對象,所以它會非常低效。

+0

那麼,如果我想讓每個對象都有多少個孩子,那麼你的解決方案是什麼? – ianaz

+1

@ianaz做什麼你會用普通的SQL做什麼。例如,你可以編寫一個查詢,返回對象與計數,例如''來自Object o,(從child where parent.id = o.id)選擇count(*)。「)。它仍然效率低下,但比指望Java方面更好。或者,您可以將查詢拆分爲兩個查詢,一個從Object o讀取所有對象'',另一個按父級對所有孩子進行分組並返回計數,例如,按父級從子組中選擇count(*)。 id「'並處理它。 –

+0

編輯:最後一個查詢應該是'「選擇parent.id,通過parent.id從子組中計數(*)」 –

1

Hibernate有一個特殊的功能,稱爲「額外懶惰」的集合,將完全按照你剛纔的建議。這意味着如果您在其中一個超懶集合上調用size(),它將返回內存中的子數,如果該集合已經初始化的話,但是如果該集合尚未初始化,將會查詢數據庫count。目的是避免初始化非常大的集合,直到絕對必要。其他例外的事情包括處理Collection.contains/Map.containsKey調用,Map.get調用,List.get(int)等調用。

爲了紀念集合作爲額外慵懶的註解,你會說@org.hibernate.annotations.LazyCollection(EXTRA)