You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SpringBoot中如何修改PUT方法实现数组批量更新?

批量更新实现方案

问题背景

现有SpringBoot服务支持单ID单条记录更新,代码如下:

Controller代码

@PutMapping("/{cveEstado}/{comentario}/{idControl}")
private void actualizaDatos(@PathVariable("cveEstado") String cveEstado, @PathVariable("comentario") String comentario,
        @PathVariable("idControl") String idControl){
    controlService.actualizar(cveEstado, comentario, idControl);
}

Service及Repository代码

// Service实现
@Override
public void actualizar(String cveEstado, String comentario, String idControl) {
    repository.actualizarCampos(cveEstado, comentario, idControl);
}

// Repository方法
@Transactional
@Modifying
@Query(value = "UPDATE CONTROL C SET CVEESTADO=?1, COMENTARIO=?2 WHERE C.IDCONTROL=?3", 
        nativeQuery = true)
void actualizarCampos(String cveEstado, String comentario, String idControl);

需求:修改为接收数组批量更新多条不同ID的记录,支持更新全部或部分字段。


具体实现步骤

1. 定义批量更新DTO

创建DTO封装单条记录的更新信息,支持部分字段为空:

public class ControlUpdateDTO {
    private String idControl; // 必传,记录ID
    private String cveEstado; // 可选,需要更新的状态
    private String comentario; // 可选,需要更新的备注

    // 构造方法、getter、setter
    public ControlUpdateDTO() {}

    public ControlUpdateDTO(String idControl, String cveEstado, String comentario) {
        this.idControl = idControl;
        this.cveEstado = cveEstado;
        this.comentario = comentario;
    }

    // 生成getter和setter方法
}

2. 修改Controller接收批量请求

将路径参数改为请求体接收DTO数组,同时修正Controller方法权限为public(Spring无法映射私有方法):

@PutMapping("/batch")
public void actualizaDatosBatch(@RequestBody List<ControlUpdateDTO> updateList) {
    controlService.actualizarBatch(updateList);
}

3. 更新Service层逻辑

新增批量更新方法,可选择两种实现方式:

@Override
@Transactional
public void actualizarBatch(List<ControlUpdateDTO> updateList) {
    // 方式一:循环调用单条更新(简单易维护,适合小批量数据)
    // updateList.forEach(dto -> {
    //     if (dto.getCveEstado() != null || dto.getComentario() != null) {
    //         repository.actualizarCampos(dto.getCveEstado(), dto.getComentario(), dto.getIdControl());
    //     }
    // });

    // 方式二:批量SQL更新(性能更优,适合大批量数据)
    repository.actualizarCamposBatch(updateList);
}

4. 实现Repository批量更新

方案A:原生SQL批量更新(单SQL语句完成)

通过CASE WHEN拼接批量更新逻辑,减少数据库交互次数:

@Transactional
@Modifying
@Query(value = """
    UPDATE CONTROL C
    SET CVEESTADO = CASE
        <foreach collection="list" item="dto" separator=" ">
            WHEN C.IDCONTROL = :#{dto.idControl} THEN :#{dto.cveEstado}
        </foreach>
        ELSE CVEESTADO
    END,
    COMENTARIO = CASE
        <foreach collection="list" item="dto" separator=" ">
            WHEN C.IDCONTROL = :#{dto.idControl} THEN :#{dto.comentario}
        </foreach>
        ELSE COMENTARIO
    END
    WHERE C.IDCONTROL IN (:ids)
    """, nativeQuery = true)
void actualizarCamposBatch(@Param("list") List<ControlUpdateDTO> updateList, @Param("ids") List<String> ids);

注:若使用Spring Data JPA原生SQL无法解析<foreach>,可通过EntityManager动态构建SQL,或改用MyBatis实现更灵活的批量SQL拼接。

方案B:JPA实体批量更新(更贴合Spring Data风格)

先查询对应实体,修改非空字段后批量保存:

// 在Repository中添加查询方法
List<Control> findAllByIdIn(List<String> ids);

// 在Service中实现批量更新逻辑
@Override
@Transactional
public void actualizarBatch(List<ControlUpdateDTO> updateList) {
    List<String> ids = updateList.stream().map(ControlUpdateDTO::getIdControl).collect(Collectors.toList());
    List<Control> controls = repository.findAllByIdIn(ids);

    controls.forEach(control -> {
        updateList.stream()
            .filter(dto -> dto.getIdControl().equals(control.getIdControl()))
            .findFirst()
            .ifPresent(dto -> {
                // 仅更新非空字段,实现部分更新
                if (dto.getCveEstado() != null) {
                    control.setCveEstado(dto.getCveEstado());
                }
                if (dto.getComentario() != null) {
                    control.setComentario(dto.getComentario());
                }
            });
    });

    repository.saveAll(controls);
}

5. 前端请求示例(Angular)

构造DTO数组发送PUT请求:

interface ControlUpdateDTO {
  idControl: string;
  cveEstado?: string;
  comentario?: string;
}

// 批量更新请求方法
updateBatch(updates: ControlUpdateDTO[]): Observable<void> {
  return this.http.put<void>('/api/control/batch', updates);
}

内容的提问来源于stack exchange,提问作者Root93

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 02:17:06