4

在我的 Web 应用程序中,我有一个与 Child 具有 OneToMany 关系的对象。选择我的对象时,我执行以下查询:

from Object o

然后我应该为每个对象打印它有多少个孩子

// Foreach
object.children.size()

假设对象有很多孩子(比如说 30'000);调用 size() 是浪费资源还是 ORM 框架(在我的例子中是 Hibernate)会在不加载所有子项的情况下处理这个问题?

4

3 回答 3

5

使用 JPA(标准):

  • 您的 @OneToMany 关系默认是延迟加载的(即 fetch=FetchType.LAZY 的默认值)。但是调用Entity.getCollection().size()会触发延迟加载以检索所有子集合 - 所以是的,它会相当慢,除非您无论如何都需要对所有/大多数元素进行操作。注意:对于 JPA 的所有(正常)实现,这不会发出 30,000 个单独的查询 - 它会发出一个在结果集中返回 30,000 行的查询。
  • 如果您需要大多数元素或者您想提前缓存更改为@OneToMany(fetch=FetchType.EAGER)
  • 在不检索每个对象的情况下获取数据统计信息的常用方法是简单地使用 JPQL via EntityManager.getQuery()/getTypedQuery()/getNamedQuery()(甚至 SQL via getNativeQUery())。这是非常简单且高性能的:
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>

然后标记哪些实体应该自动缓存在二级缓存中:

@Cacheable(true)
@Entity
public class Employee {
    ...
}
  • 还可以动态配置缓存,作为特定查询的一部分

使用专有方法(例如 Hibernate “Extra-Lazy” 集合):

  • 与简单地发出 JPQL/SQL 查询的性能相同
  • 保存几行代码(@org.hibernate.annotations.LazyCollection(EXTRA) 注释 v @NamedQuery 注释和执行)
  • 不标准 - 受过 JPA 培训的开发人员不会知道它
  • 不可移植 - 只能与该供应商一起使用。远离专有特性的行业趋势是标准 JPA。那里有许多不同的 JPA 实现。
于 2012-11-02T23:01:52.367 回答
2

在 JPA 实现中启用日志消息并查看真正发送到数据库的数据库查询总是一个好主意。在您的情况下,我会说 ORM 可能会延迟加载所有对象,因此效率会非常低。

于 2012-10-31T11:41:12.783 回答
1

Hibernate 有一个特殊的特性,称为“额外的惰性”集合,它可以完全按照您的建议进行操作。这意味着如果您调用size()这些超惰性集合之一,如果集合已经初始化,它将返回内存中的子节点数,但如果集合尚未初始化,它将查询数据库count。目的是避免在绝对必要之前初始化非常大的集合。其他一些非常懒惰的例子包括处理Collection.contains/Map.containsKey调用、Map.get调用List.get(int)等调用。

要使用注释将集合标记为超级懒惰,您会说@org.hibernate.annotations.LazyCollection( EXTRA )

于 2012-11-01T12:10:12.603 回答