使用Hibernate 4.1&带有实体管理器的JPA 2.0,将子实体加载到多个级别的多个实体的最佳加载方式是什么?

时间:2012-07-14 21:59:28

标签: hibernate jpa-2.0 hibernate-entitymanager

我们正在使用Hibernate 4.1.4和实体管理器实现,并对它非常满意。当加载单个实体或一小组实体(10-50 +子实体)时,我们获得了出色的性能,并且我们所有的连接都很好并且是双向的。编辑/保存/删除是轻而易举的事!

加载2500个实体&报告的相关数据

当我们尝试加载数百或数千个实体以及子实体时,我们遇到了问题。在一个示例中,我们具有大约2500个基本实体以及两个一对一和三个一对多连接。这导致2500 x 5 +1查询。使用我们的数据库(DB2)执行大约需要30秒。

我们使用动态查询,实体管理器创建查询方法:

http://docs.jboss.org/hibernate/orm/4.1/javadocs/

http://docs.oracle.com/javaee/6/api/javax/persistence/EntityManager.html

试图诱使Hibernate使用联接

我们的观察结果是,无论我们尝试什么,我们似乎都无法通过hibernate来执行子实体的加载作为主查询的连接。当使用find方法和主键加载单个实体时,hibernate使用连接,但是当加载多个基本实体时,它不会。

我们尝试过具有相同结果的标准api。

在查询中检索多个实体的成功

示例:

select a,b from table1 a left join table2 b

我们在查询中手动连接并通过元组检索单个实体取得了部分成功,但这绕过了带注释的实体模型,并不是首选方法(如果可以避免的话)。

http://docs.jboss.org/hibernate/orm/4.1/manual/en-US/html_single/#objectstate-querying-executing

我们遇到的元组问题是它们与主要实体分离(这似乎是合乎逻辑的,因为它们没有通过注释关系加载)并且似乎无法重新附加它们。在实体列表中手动添加所有一对多记录后,当hibernate命中列表的get方法时,它仍然会尝试急切/延迟加载列表(尽管已经设置了列表)。

尝试优化 - 预加载数据集

我们尝试的另一种优化技术是预先加载数据集。加载所有核心实体后,我们构建了一个pk列表,并关闭了一个查询以加载所有一对多数据集。但是当hibernate再次访问列表数据的getter时,它再次尝试急切/延迟加载列表,忽略会话中已经预先加载的内容(可能需要启用缓存?)。

建议吗

我们正朝着许多不同的方向前进,收效甚微,并希望有人能指出我们正确的道路(或指出一个新的道路!)!

1 个答案:

答案 0 :(得分:1)

好像我自己已经弄清楚了!两个策略解决了这个问题:

  1. 在查询中加入fetch会处理一对多的连接!当然你只能做一次连接获取,因为Hibernate会抛出无法同时获取多个包异常。

    示例:

    LEFT OUTER JOIN FETCH t.table3 t3
    
  2. 对于其他联接@Fetch(FetchMode.SUBSELECT)做了诀窍!

  3. 有效地将总查询数量从几千个减少到几个。在一个示例中,选择了188个核心实体,并且执行了总共12个查询。额外的查询主要是一对一的查找,并且对总执行时间(平均1-2秒)没有显着影响。无论选择188还是1888记录,查询总数都不会显着增加。

    如果有人想了解更多信息,请随时与我联系或发表评论! :)