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

r7knjye2  于 2021-07-24  发布在  Java
关注(0)|答案(1)|浏览(1751)

问题:我有一个进程正在运行,它会定期从外部获取500条记录并将其插入数据库。如何使用spring jpa有效地检查下面的案例,
如果没有记录(非主键列也是唯一的),如何插入数据?
如果有记录,如何只更新一些字段?

如何使用springjpa对所有列或仅选定列上的批量记录进行saveorupdate?

v1l68za4

v1l68za41#

如果你查一下 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 .
要更好地控制上述upsert行为,可以使用 @DynamicUpdate 实体类上的注解,这意味着jpa生成的updatesql将只访问更改的列。
以上信息不足以在您的情况下正确使用jpa。如果选择jpa,则必须在 object 是的。为了处理这500条记录 unique 必须由以下条件之一定义:
主键
唯一约束
我建议您使用第二个,因为主键用于在数据库级别标记unique。然后,使用jpa,您应该在数据库中找到新的500条记录中存在的数据,更新它们的修改列,使用 saveAll() 更新它们。然后处理左边的部分,构建实体并使用 saveAll() 插入它们。
你可能已经注意到 compare and update then save operation in memory 我上面使用的方法不是原子的,可能会导致 ConstraintViolationException 插入重复数据时,有两种处理方法:
如果数据不是那么严重,您可以只执行上述操作,但为异常的发生保留一些空间,您可以记录信息以进行手动修复,也可以不执行任何操作。但是记住捕获异常,不要使更新操作回滚。
如果您确实对数据很认真,那么可以使用 synchronized 关键字或分布式锁。
老实说,我对批处理upsert上的jpa不满意,它不原子,不安全,也不快。我认为这是因为没有一个通用的 upsert 模式,从而orm部分放弃了该功能。我真诚地推荐你使用 upsert 使用系统选择的数据库实现的原始sql操作,如mysql insert。。。重复键更新语句。示例代码如下:

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());
  }

相关问题