Hibernate Mass Insert/update:这是一个很好的方法吗?

Chr*_*oph 5 java sql hibernate jdbc

我目前正在基于hibernate的应用程序中进行性能和内存调整,以进行大批量/批量导入.我们基本上导入一个带有产品数据的CSV文件,其中一些产品是新的(插入),一些是存在的(更新).

我现在的重点是选择一个策略来找出要更新的实体和要插入的实体,而不对CSV文件中的每一行进行检查(选择是否存在).

我目前的做法是这样的:

  1. 构建数据库中所有对象的哈希映射.
  2. 迭代CSV并使用hashmap决定是更新还是插入.

这种方法效果很好,并且测试证明它比每行进行这样一次IF EXISTS检查的速度快.

如果数据库中有很多实体,我关心的是内存大小.

现在我考虑使用上述方法的略微变化,我想知道意见.基本上我想做的是用多行进行多批IF EXISTS检查(例如SELECT FROM table where sku IN (sku1, sku2, sku3))

这是一些伪代码:

1. Database contains: db{sku1, sku2,sku3,sku5}

2. file contains: file {sku1, sku2, sku3, sku6}

3. Expected result: 
   updates: {sku1, sku2, sku3}
   inserts{sku6}

4. Algorithm

   have a map to keep database entities which need updates
   updatemap {}
   now iterate over the file in e.g. batches of 2 rows (for demo purposes)
   1st iteration: foreach (select where sku IN (sku1, sku2) limit 2) as elem
    -> updatemap.add(elem)  -> elem is asumed to be a persistent entity here
    -> myDAO.update(elem)   -> executes Spring's getHibernateTemplate().update() under the hood

   -> updatemap contents after 1st loop {sku1, sku2}

   2nd iteration: foreach (select where sku IN (sku3, sku6) limit) 2 as elem
    -> updatemap.add(elem)    
    -> myDAO.update(elem)

   -> updatemap contents after 3nd loop {sku1, sku2, sku3}
Run Code Online (Sandbox Code Playgroud)

顺便说一下:我也已经假设了类似的东西 (if i % 30 == 0) session.flush; session.clear();

现在我们知道所有已更新的元素.不在updatemap中的所有skus基本上都是插入的,我们可以使用简单的集算术来确定那些

file {sku1,sku2,sku3,sku6} - updatemap {sku1,sku2,sku3} = newinserts {sku6}

现在我们可以继续为剩余的CSV行插入.

结论 我的假设是,由于文件内容的分块,我可以限制使用的内存量.我有比我最初的方法更多的SELECT语句,但是如果数据库中已有数千个实体,我可以更好地控制内存使用.

你对此有何看法?还有哪些有效的方法来确定要更新哪些实体以及批量插入哪些实体?

Mar*_*nik 2

我遇到了完全相同的问题,涉及数百万条记录,并且与您几乎完全一样地解决了它。对于旁观者来说,一个可能不明显的限制是我们不能使用常规的 Hibernate 加载-变异-更新方式,因为这会产生过多的冗余流量。

仔细阅读后,我的方法与您的方法不同,因为除了处理单个块之外,我不保留任何信息。在继续处理下一个块之前,我会完整处理该块,包括所有插入和更新。只有这样,您才能拥有可扩展的解决方案。

对我来说最弱点是使用executeUpdate,它不会使用 JDBC 批处理 API。我原本计划进行自定义实现,但对于我的特定用例,结果证明我不需要每个executeUpdate块使用多个。