Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/334.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Spring Jpa批量插入整个数据或更新实体的某些字段(如果已经可用)_Java_Spring_Spring Boot_Spring Data Jpa - Fatal编程技术网

Java 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(实体); 返回实

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

  • 如果没有记录(非主键列也是唯一的),如何插入数据
  • 如果有记录,如何仅更新某些字段

  • 如何使用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
    的信号必须由以下条件之一定义:

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

    您可能已经注意到,我上面使用的
    比较和更新然后在内存中保存操作
    方法不是原子的,并且在插入重复数据时可能会导致
    ConstraintViolationException
    ,有两种方法可以处理此问题:

    • 如果数据不是那么严重,您可以只执行上面的操作,但为异常的发生保留一些空间,您可以记录信息以进行手动修复,也可以不执行任何操作。但是请记住捕获异常,不要使更新操作回滚
    • 如果您确实认真对待数据,可以使用
      synchronized
      关键字或分布式锁来同步整个操作
    老实说,我对批处理上传的JPA不满意,它不是原子的,不安全,也不快速。我认为这是因为在所有的DBMS中都没有一个普遍实现的
    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作为数据库,合并可以作为重复密钥更新的替代方案吗?