Hibernate批量保存嵌套对象

时间:2017-02-28 16:50:44

标签: java hibernate batch-processing

我有以下类结构:

class A{
    int id;
    List<B> blist;
    List<C> clist;
    List<D> dlist;
}

我得到一个json作为输入,由mapper映射到对象 A 。现在,我有对象 A ,其中包含 B,C和D 对象的列表。我想使用批处理来节省插入时间。如果我想保存多个父对象,我浏览了描述解决方案的documentation。我如何在我的情况下使用批处理功能,它具有嵌套的多种类型的对象列表。

我已使用

启用批量插入
<property name="hibernate.jdbc.batch_size">50</property>

除非我清除并刷新会话,否则这本身并不会给我任何批处理。关于如何解决这个问题的任何建议?

1 个答案:

答案 0 :(得分:1)

问题是您正在使用IDENTITY策略。

无论何时保存新实体,Hibernate都会将其放入Session的1LC;但是,为了做到这一点,必须知道标识符。 IDENTITY策略的问题是Hibernate必须实际执行插入以确定标识符值。

最后,批量插入功能被禁用。

您应该尝试使用事先已知的业务键值或使用序列优化器的最坏情况使用SEQUENCE生成类型来加载数据,以最大限度地减少数据库命中。这将允许批量插入工作。

更新

如果您没有定义行唯一性的业务键,而您的数据库没有SEQUENCE支持,则可以自行管理标识符。您可以选择使用自定义标识符生成器执行此操作,也可以选择在循环中执行此操作作为代码。

这里需要注意的是此解决方案线程安全。你应该保证在任何时候你都不会同时在两个线程中运行这个逻辑,这通常不是人们在批量数据加载时所做的事情。

  1. 定义一个变量来存储您的标识符。我们需要根据数据库中标识符的现有最大值来初始化此变量。如果数据库中没有行,我们可能希望将其初始化为1。

    Long value = ... // createQuery ( "SELECT MAX(id) FROM YourEntity" )
    value = ( value == null ? 1L : value + 1);
    
  2. 下一步是更改@Id带注释的字段。它不应该标记为@GeneratedValue,因为我们将允许应用程序提供值。

  3. 对于您要插入的每一行,只需使用步骤1中生成的值变量调用#setId( value )方法。

  4. value变量增加1。

相关问题