Hibernate 批量保存嵌套对象

Hibernate Batch Save Nested Objects

我有以下 class 结构:

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

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

我使用

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

这本身不会给我任何批处理,除非我清除并刷新会话。关于如何处理这个问题有什么建议吗?

问题是您正在使用 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。