0

我正在使用 Java 和 Hibernate 的 JPA 实现构建一个数据库 Web 应用程序。应用程序跟踪对象。它还必须从遗留源批量导入对象。

例如,假设我们正在跟踪人员。该数据库有名为 Person 和 Address 的表。有对应的 JPA 实体和 DAO 类。

在 JPA 层之上是负责各种操作的服务层。一个操作是从外部遗留源(例如电话簿中的人)导入一组可能很大的数据。对于每个人,它必须检查它是否已经存在于数据库中。然后它必须根据需要创建或更新人员。每个人都有一个地址,因此还必须进行适当的交叉引用和地址创建。

我的问题是,对于大型数据集,此操作可能会很慢。我目前的算法是:

for (Person person: allPersons)
{
    check if person exists in database
    check if address exists in database
    create or update person and address as necessary
}

你会建议什么来提高性能?

在我的脑海中,我能想到:

  1. 更改导入逻辑以使用查询检索数据并将其存储到数据库。例如,不是在 for 循环中检查人员是否存在,而是在一个查询中将所有人员键提交到数据库,该过程每个检索到的人员在内存中。
  2. 在 DAO 类中添加我自己的缓存。
  3. 使用外部缓存解决方案(例如 memcached)。

我总是可以通过重组以最小化查询来选择#1。缺点是我的服务层现在非常了解 DAO 层。它的实现现在由较低的数据库层决定。还有其他问题,例如使用过多的内存。这种从数据库中抓取然后在内存中处理的方法似乎非常本土化,并且与 JPA 等现成的解决方案背道而驰。我很好奇其他人在这种情况下会怎么做。

编辑:缓存无济于事,因为在循环中被查询的每个人都是不同的。

4

2 回答 2

1

我发现有两种解决方案有效。一种是一次处理一个块。每个块关闭后重新启动会话。我曾尝试在会话中使用 flush clear 方法,但有时它的功能与您预期的一样。在批次之间启动和停止事务似乎效果最好。

如果性能是一个主要问题,您只需分解并在 JDBC 中执行。Hibernate 为大型数据集的批处理增加了太多开销,其中内存和性能很重要。

于 2008-12-23T03:46:28.600 回答
0

您的方法将导致对数据库的单独查询过多;看起来像 4n + 1。如果可能,我会编写一个查询(可能在原始 SQL 中),一次性检查人员 + 地址是否存在。

您可能希望使用 StatelessSession 而不是标准的 Hibernate Session。由于它没有一级缓存,它应该可以降低您的内存需求。

http://www.hibernate.org/hib_docs/reference/en/html/batch-statelesssession.html

如果这对您不起作用,那么您需要查看 Hibernate 中的批处理选项:

http://www.hibernate.org/hib_docs/reference/en/html/batch.html

于 2009-01-01T06:10:58.020 回答