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传递回后端。
修复步骤
在更新页面的表单中添加隐藏的主键字段
假设使用Thymeleaf模板,在updatePatient.html的表单内添加:<input type="hidden" th:field="*{patientId}" />该字段会自动绑定从控制器传入的Patient对象的
patientId,提交时将其带回后端。验证提交的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; }删除仓库接口中的冗余方法
JpaRepository已经提供了findAll()、deleteById()、count()、findById()、save()等方法,无需在自定义仓库中重复定义,避免潜在的方法冲突。
内容的提问来源于stack exchange,提问作者AnkaraUniFedaisi
相关产品推荐
相关产品推荐

