繁体   English   中英

Spring Jpa 批量插入整个数据或更新实体的某些字段(如果已经可用)

[英]Spring Jpa Bulk Insert whole data or Update some fields of entity if already available

问题:我有一个正在运行的进程,它会定期从外部抓取 500 条记录并将其插入数据库。 如何使用 spring JPA 在以下情况下有效检查,

  1. 如果没有记录(非 primary_key 列也是唯一的),如何插入数据?
  2. 如果有记录,如何只更新某些字段?

或者

如何使用 Spring JPA 对所有列或仅选定列的批量记录进行保存或更新?

如果您查看Spring Data JPA的源代码,您会发现:

@Transactional
public <S extends T> S save(S entity) {

  if (entityInformation.isNew(entity)) {
    em.persist(entity);
    return entity;
  } else {
    return em.merge(entity);
  }
}

save操作是添加和更新的混合。 因此,通过使用save()saveAll()方法,您已经实现了saveOrUpdate的 function。

要更好地控制上述 upsert 行为,您可以在实体 class 上使用@DynamicUpdate注释,这意味着由 JPA 生成的更新 SQL 将仅访问更改的列。

以上信息不足以在您的情况下正确使用 JPA。 如果选择 JPA,则必须以object方式进行数据库访问。 要处理 500 条记录, unique信号必须由以下条件之一定义:

  • 主键
  • 唯一约束

我建议您使用第二个,因为主键用于在数据库级别标记唯一性。 然后,使用 JPA,您应该在数据库中找到新的 500 条记录中存在的数据,更新它们修改的列,使用saveAll()更新它们。 然后处理左侧部分,构建实体并使用saveAll()插入它们。

您可能已经注意到我上面使用compare and update then save operation in memory不是原子的,并且在插入重复数据时可能会导致ConstraintViolationException ,有两种处理方法:

  • 如果数据不是那么严重,您可以只执行上述操作,但为异常发生保留一些空间,您可以记录信息以进行手动修复或什么也不做。 但记住要捕获异常,不要让更新操作回滚。
  • 如果你确实对数据很认真,你可以使用synchronized关键字或分布式锁来使整个操作同步。

老实说,我对批量 upsert 上的 JPA 不满意,它不是原子的,不安全的,也不快。 我认为这是因为在所有 DBMS 中都没有普遍实现的upsert模式,因此 ORM 部分放弃了 function。 我真诚地建议您对系统选择的数据库实现的原始 SQL 使用upsert操作,例如 MYSQL INSERT... ON DUPLICATE KEY UPDATE Statement 下面的示例代码:

  public int upsert(List<Employee> employees) {

      String sqlPattern = "INSERT INTO employee (id, code, name)\n" 
              + "VALUES %s\n"
              + "ON DUPLICATE KEY UPDATE name      = values(name);";

      List<String> values = employees.stream()
              // build something like (1, '10001', 'Foo Bar')
              .map(employee -> buildRecord(employee))
              .collect(Collectors.toList());

      String sql = String.format(sqlPattern, StringUtils.join(values, ", "));

      return jdbcTemplate.update(sql, Map.of());
  }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM