2012-10-31 89 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)