我正在使用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来最小化查询。缺点是我的服务层现在非常了解DAO层。它的实现现在由较低的数据库层决定。还有其他问题,如使用太多内存。这种从内存中获取的数据库然后进程似乎非常本土化,并且违背JPA等现成的解决方案。我很好奇其他人在这种情况下会做些什么。
编辑:缓存无效,因为在循环中查询的每个人都不同。
答案 0 :(得分:1)
我找到了两种解决方案。一种是一次处理一个块。每个块关闭后重新启动会话。我试图在会话中使用flush clear方法,但有时它只是像你期望的那样运行。在批次之间启动和停止交易似乎效果最好。
如果性能是一个主要问题,那么您只需要在JDBC中进行分解。 Hibernate为大型数据集的批处理增加了太多开销,其中内存和性能很重要。
答案 1 :(得分:0)
您的方法会导致针对数据库的单个查询过多;看起来像4n + 1.如果可能的话,我会写一个查询(可能是在原始SQL中),一次性检查人员+地址的存在。
您可能希望使用StatelessSession而不是标准的Hibernate会话。由于它没有第一级缓存,因此应该降低内存需求。
http://www.hibernate.org/hib_docs/reference/en/html/batch-statelesssession.html
如果这对您不起作用,那么您将需要查看Hibernate中的批处理选项:
http://www.hibernate.org/hib_docs/reference/en/html/batch.html