我有几个客户希望使用CSV文件更新他们的数据,典型客户的文件有1.000到20,000行。
解析行后,我将新的新数据合并到现有实体中。已修改的所有实体都使用批量保存保存:
public void batchSaveOrUpdate(List<Item> items) {
Transaction transaction = session.beginTransaction();
List<Item> itemsToEvict = new ArrayList<>();
int count = 0;
for (Item item : itemss) {
session.saveOrUpdate(item);
itemsToEvict.add(item);
if (count++ % 25 == 0) {
session.flush();
itemsToEvict.forEach(session::evict);
itemsToEvict.clear();
}
}
transaction.commit();
session.flush();
}
适用于最多25.000行的正常导入,但现在我有一个客户,哪个CSV文件包含多达600.000行。 即使在确定已修改的项目之后,仍有100,000个实体可以立即更新。 由于一段时间后WildFly会收到所有交易,因此大客户的所有进口都会失败。 我已经将事务超时时间增加到一小时,并且进一步增加对我来说无法解决。
此时我可以做些什么来增加hibernate更新预先性能?
答案 0 :(得分:1)
确保您实际使用的是批处理。正确配置与批次相关的属性:
<property name="hibernate.jdbc.batch_size">100</property>
<property name="hibernate.order_inserts">true</property>
<property name="hibernate.order_updates">true</property>
我已将jdbc.batch_size
设置为100;在您刷新会话之前,此值应与处理项目的计数相匹配(在您的情况下为25;或许您应该尝试更多,例如100)。
此外,您正在明确驱逐项目。如果Item
与其他实体相关联,并且在关联上未指定级联类型ALL
和DETACH
,则驱逐将不会级联到相关实体,并且它们将消耗大量堆,因为Hibernate会将它们保留在持久化上下文(会话)中,因此如果存在数十万个应用程序性能,则会显着降低应用程序性能。
确保分离(逐出)整个对象图,或清除整个会话并阅读下一个要处理的项目块。
答案 1 :(得分:1)
您可以尝试编写自己的存储过程。 Hibernate不是最适合您的需求..
答案 2 :(得分:1)
首先,CopyManager是将CVS复制到postgres的最有效方法。可能是您应该创建一些临时表,然后复制CSV然后执行一组插入/更新SQL语句。获取PGConnection和CopyManager可能很棘手。例如。如果您使用c3p0连接池,则无法实现。
根据Chapter 4. Batch Processing:
也很重要如果使用身份标识符生成器,Hibernate会透明地禁用JDBC级别的插入批处理。