Spring,Hibernate - 批量处理大量具有良好性能的数据

时间:2012-01-10 07:38:13

标签: spring hibernate transactions batch-processing large-data

想象一下,你在数据库中有大量的数据。 〜100MB。我们需要以某种方式处理所有数据(更新或导出到其他地方)。如何以良好的性能实现此任务?如何设置事务传播?

示例1#(性能不佳):

@Singleton
public ServiceBean {

 procesAllData(){

   List<Entity> entityList = dao.findAll();

   for(...){
     process(entity);
   }

 }

 private void process(Entity ent){
  //data processing    
  //saves data back (UPDATE operation) or exports to somewhere else (just READs from DB)
 }

}

这里有什么可以改进的?

在我看来:

  1. 我会设置hibernate批量大小(请参阅hibernate文档进行批处理)。
  2. 我将ServiceBean分成两个具有不同事务设置的Spring bean。方法processAllData()应该用完事务,因为它运行大量数据并且潜在的回滚不会“快速”(我猜)。方法进程(实体实体)将在事务中运行 - 在一个数据实体的情况下进行回滚没什么大不了的。
  3. 你同意吗?有什么提示吗?

2 个答案:

答案 0 :(得分:2)

以下是两个基本策略:

  1. JDBC批处理:设置JDBC批处理大小,通常介于20到50之间(hibernate.jdbc.batch_size)。如果要混合和匹配对象C / U / D操作,请确保已配置Hibernate以订购插入和更新,否则不会批处理(hibernate.order_insertshibernate.order_updates)。在进行批处理时,必须确保clear() Session Work,以便在大型事务中不会遇到内存问题。
  2. 连接的SQL语句:实现Hibernate doWork接口并使用您的实现类(或匿名内部类)来针对JDBC连接运行本机SQL。通过分号连接手工编码的SQL(适用于大多数DB),然后通过{{1}}处理该SQL。此策略允许您使用Hibernate事务协调器,同时能够充分利用本机SQL的强大功能。
  3. 您通常会发现无论您获得OO代码的速度有多快,使用连接SQL语句等DB技巧都会更快。

答案 1 :(得分:1)

这里有几点需要注意:

  1. 使用findAll方法将所有entites加载到内存中可能会导致OOM异常。

  2. 您需要避免将所有实体附加到会话中 - 因为每次hibernate执行刷新时都需要脏检查每个附加的实体。这将很快使您的处理停止。

  3. Hibernate提供了一个无状态会话,您可以使用可滚动的结果集逐个滚动实体 - docs here。然后,您可以使用此会话更新实体,而无需将其附加到会话。

    另一种方法是使用有状态会话,但定期清除会话,如here所示。

    我希望这是有用的建议。