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

Spring Data JPA更新患者数据时重复创建数据问题求助

问题:更新患者数据时创建新条目而非更新

开发的应用中,创建、删除患者数据功能正常,但尝试更新现有患者数据时,代码会创建一条新的患者数据,导致数据库出现重复条目。

患者实体类

package com.laboratory.app.entity;
import jakarta.persistence.*;
import lombok.*;
import java.time.LocalDate;

@Entity
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
@Table(name="patient")
public class Patient {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long patientId;

    @Column(name="FileNo")
    private int fileNo;
    @Column(name="PatientName", nullable=false)
    private String patientName;
    @Column(name="PatientSurname", nullable=false)
    private String patientSurname;
    @Column(name="PatientDisease", nullable=false)
    private String patientDisease;
    @Column(name="DiagnosisInfo", nullable=false)
    private String diagnosisInfo;
    @Column(name="PatientSecurityNumber", nullable=false)
    private Long patientSecurityNumber;
    @Column
    private LocalDate dateAdded;

}

仓库接口

package com.laboratory.app.repository;
import com.laboratory.app.entity.Patient;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;

@Repository
public interface PatientRepository extends JpaRepository<Patient, Long> {

    List<Patient> findAllByOrderByDateAddedAsc(); // 按日期升序展示数据
    List<Patient> findAllByOrderByDateAddedDesc(); // 按日期降序展示数据

    // 按姓名模糊查询(忽略大小写)
    List<Patient> findAllByPatientNameContainingIgnoreCase(String name);
    List<Patient> findAllByPatientSurnameContainingIgnoreCase(String name);

}

注:JpaRepository已自带findAll()、deleteById()、count()、findById()、save()等方法,无需重复定义,冗余代码可删除。

服务类

package com.laboratory.app.service;
import com.laboratory.app.entity.Patient;
import com.laboratory.app.repository.PatientRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;

@Service
public class PatientService {
    @Autowired
    PatientRepository patientRepository;

    public List<Patient> listAllPatients() {
        return patientRepository.findAll();
    }

    public void savePatient(Patient patient) {
        patientRepository.save(patient);
    }

    public void deletePatient(Long id) {
        patientRepository.deleteById(id);
    }

    public long getPatientNum() {
        return patientRepository.count();
    }

    public Optional<Patient> findPatientById(Long id) {
        return patientRepository.findById(id);
    }

    public List<Patient> findPatientByName(String name) {
        return patientRepository.findAllByPatientNameContainingIgnoreCase(name);
    }

    public List<Patient> findPatientBySurname(String surname) {
        return patientRepository.findAllByPatientSurnameContainingIgnoreCase(surname);
    }

    public List<Patient> getAllPatientsSortedByDateAdded(boolean ascending) {
        if (ascending) {
            return patientRepository.findAllByOrderByDateAddedAsc();
        } else {
            return patientRepository.findAllByOrderByDateAddedDesc();
        }
    }

}

控制器类

package com.laboratory.app.controller;
import com.laboratory.app.entity.Patient;
import com.laboratory.app.service.PatientService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import java.util.List;

@RestController
public class PatientController {

    @Autowired
    private PatientService patientService;

    @GetMapping(value="/register_patient")
    public ModelAndView registerPatient(Model model) {
        ModelAndView registerView = new ModelAndView("patient/registerPatient");
        Patient newPatient = new Patient();
        model.addAttribute("patient", newPatient);
        return registerView;
    }

    @PostMapping(value="/save")
    public ModelAndView savePatient(@ModelAttribute("patient") Patient patient) {
        patientService.savePatient(patient);
        ModelAndView view = new ModelAndView("patient/doneSuccessfully");
        return view;
    }

    @GetMapping(value="/delete")
    public ModelAndView deletePatient(@RequestParam("patientId") String id) {
        ModelAndView view = new ModelAndView("patient/deleted");
        patientService.deletePatient(Long.valueOf(id));
        return view;
    }

    @GetMapping(value="/view_database")
    public ModelAndView viewDatabase(Model model) {
        List<Patient> theEmployees = patientService.listAllPatients();
        model.addAttribute("patients", theEmployees);
        ModelAndView view = new ModelAndView("viewDatabase");
        return view;
    }

    @GetMapping(value="/update")
    public ModelAndView updateDatabase(@RequestParam("patientId") String id, Model model) {
        ModelAndView view = new ModelAndView("patient/updatePatient");
        Patient updatedPat = patientService.findPatientById(Long.valueOf(id)).get();
        model.addAttribute("patient", updatedPat);
        return view;
    }
}

解决方案

问题原因

Spring Data JPA的save()方法判断执行更新还是插入的核心依据是:实体的主键是否存在且不为null。如果提交的Patient对象patientId为null,save()会默认执行插入操作,创建新条目。当前问题大概率是更新页面的表单没有将patientId传递回后端。

修复步骤

  1. 在更新页面的表单中添加隐藏的主键字段
    假设使用Thymeleaf模板,在updatePatient.html的表单内添加:

    <input type="hidden" th:field="*{patientId}" />
    

    该字段会自动绑定从控制器传入的Patient对象的patientId,提交时将其带回后端。

  2. 验证提交的Patient对象主键
    可在控制器的savePatient方法中临时打印日志,确认patient.getPatientId()是否有值:

    @PostMapping(value="/save")
    public ModelAndView savePatient(@ModelAttribute("patient") Patient patient) {
        System.out.println("提交的Patient ID: " + patient.getPatientId()); // 验证主键是否存在
        patientService.savePatient(patient);
        ModelAndView view = new ModelAndView("patient/doneSuccessfully");
        return view;
    }
    
  3. 删除仓库接口中的冗余方法
    JpaRepository已经提供了findAll()、deleteById()、count()、findById()、save()等方法,无需在自定义仓库中重复定义,避免潜在的方法冲突。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 19:15:08