对于春季CrudRepository.saveAll方法,批处理对于具有未生成ID的实体

时间:2019-12-13 10:15:51

标签: spring hibernate spring-boot jpa hibernate-jpa

我发现了一些问题,我想知道我是否只是想丢失一些东西,或者这是一个真正的问题,可以通过某种方式解决。

项目已配置批处理:

spring.jpa.properties.hibernate.jdbc.batch_size=50
spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.order_updates=true
spring.jpa.properties.hibernate.jdbc.batch_versioned_data=true

,它正在工作。但是我们有一些实体没有生成ID,例如:

@Entity
public class SomeEntity {

    @Id
    private String id;

    //...
}

并说,我们从用户那里获得了1,000,000,并且希望将其插入,或者更糟糕的是使用现有的UPDATE。因此,我们将使用org.springframework.data.repository.CrudRepository#saveAll。将会发生什么:

  1. saveAll将循环调用save
  2. 每个save都会呼叫entityInformation.isNew(entity),如果持续发出,则每次呼叫都会得到响应false
  3. save将为每个实体调用合并。
  4. IIUC,这些merge调用首先被选择,而那些不能被批量处理,因此将产生N + 1个问题。将有100万个选择,然后是正确的批处理插入。

现在如何解决它?

现在考虑更新的可能性:如果我知道我正在使用这样的实体(具有未生成的ID),则可以覆盖发出简单saveAll的{​​{1}}方法,以找出哪个实体 实际上存在于系统中,对那些实体进行批量合并(即,使用select id from ... where id in ()将所有实体引入持久性上下文,然后在它们上调用findAllById-一次),然后批处理与那些没有的批处理(简单的em.merge循环)一起保存。

但是我不是JPA专家,所以有以下问题:

  1. 这样可以吗,还是我实际上忽略了某些东西,并且有一些更自然的方法来解决此问题?
  2. 如果我是对的并且必须修复saveAll方法,那么我不想在每个存储库中实现它,因此我将创建一些新的基本存储库实现。 em.persist井即使对于具有非生成IDs IIUC的实体也应该是固定的,以便在插入/更新混合在一起时实际发生批处理。可以说我不想有两个根,一个根用于生成的实体,第二个用于非生成ID的实体。有没有一种方法,如何找出实体是否使用生成的ID?可能可以简化查找方法,如果ID字段分配了生成器?

谢谢!

0 个答案:

没有答案