Java Spring Jpa批量插入整个数据或更新实体的某些字段(如果已经可用)
问题: 我有一个进程正在运行,它将定期从外部抓取500条记录并将其插入数据库。 如何使用spring JPA有效地检查下面的案例Java Spring Jpa批量插入整个数据或更新实体的某些字段(如果已经可用),java,spring,spring-boot,spring-data-jpa,Java,Spring,Spring Boot,Spring Data Jpa,问题: 我有一个进程正在运行,它将定期从外部抓取500条记录并将其插入数据库。 如何使用spring JPA有效地检查下面的案例 如果没有记录(非主键列也是唯一的),如何插入数据 如果有记录,如何仅更新某些字段 或 如何使用Spring JPA保存或更新所有列或仅选定列上的批量记录?如果查看Spring Data JPA的源代码,您会发现: @Transactional 公共存储(S实体){ if(entityInformation.isNew(实体)){ em.persist(实体); 返回实
如何使用Spring JPA保存或更新所有列或仅选定列上的批量记录?如果查看
Spring Data JPA
的源代码,您会发现:
@Transactional
公共存储(S实体){
if(entityInformation.isNew(实体)){
em.persist(实体);
返回实体;
}否则{
返回em.merge(实体);
}
}
save
操作是添加和更新的混合。因此,通过使用方法save()
或saveAll()
,您已经实现了saveOrUpdate
的功能
为了更好地控制上述upsert行为,您可以在实体类上使用@DynamicUpdate
注释,这意味着JPA生成的更新SQL将只访问更改的列
以上信息不足以在您的情况下正确使用JPA。如果选择JPA,则必须以object
的方式访问数据库。要处理500条记录,unique
的信号必须由以下条件之一定义:
- 主键
- 唯一约束
saveAll()
更新它们。然后处理左侧部分,构建实体并使用saveAll()
插入它们
您可能已经注意到,我上面使用的比较和更新然后在内存中保存操作
方法不是原子的,并且在插入重复数据时可能会导致ConstraintViolationException
,有两种方法可以处理此问题:
- 如果数据不是那么严重,您可以只执行上面的操作,但为异常的发生保留一些空间,您可以记录信息以进行手动修复,也可以不执行任何操作。但是请记住捕获异常,不要使更新操作回滚
- 如果您确实认真对待数据,可以使用
关键字或分布式锁来同步整个操作synchronized
upsert
模式,因此ORM部分放弃了这个功能。我真诚地建议您使用upsert
操作,使用系统选择的数据库(如MYSQL)实现的原始SQL。示例代码如下:
public int upert(列出员工){
String sqlPattern=“插入员工(id、代码、名称)\n”
+“值%s\n”
+“在重复密钥上更新名称=值(名称);”;
列表值=employees.stream()
//构建类似(1,'10001,'foobar')
.map(员工->构建记录(员工))
.collect(Collectors.toList());
stringsql=String.format(sqlPattern,StringUtils.join(值,“,”);
返回jdbcTemplate.update(sql,Map.of());
}
谢谢您的评论。因此,我可以想到的一种方法是使用存储过程进行UPSERT,并从Spring调用该过程。你认为这还是最好的表现吗?就像再次给SP而不是应用层带来负担一样。在通过spring调用存储过程时,是否可以发送类似对象列表的列表?存储过程将逻辑与代码分离,虽然效率很高,但很难调试,因此我建议您编写原始SQL(在答案中更新),并直接执行原始SQL@Satscreateso使用本机sql查询抓取、比较、插入或更新是正确的方法吗?不,比较是通过sql和代码列上的唯一约束实现的。只要抓取数据并执行sql,就会插入新数据,更新旧数据@SATSCreate在我的情况下,我使用Microsoft SQL server作为数据库,合并可以作为重复密钥更新的替代方案吗?