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

Spring Boot + MongoDB CRUD应用更新与删除异常排查求助

Spring Boot + MongoDB CRUD 问题排查与解决

问题分析

你遇到的两个核心问题根源一致:实体类未正确配置MongoDB主键映射,导致基于ID的操作(更新、删除)无法正确识别目标文档:

  1. 更新操作创建新对象:MongoDB的save()方法会根据主键判断是更新还是插入,由于你的自定义id字段未被设为主键,每次调用save()都会生成新的MongoDB默认主键_id,从而插入新文档。
  2. 删除操作返回500错误:deleteById()是基于主键执行删除,但你的id不是主键,且主键类型不匹配(MongoDB默认主键为ObjectId,你用了int类型),导致类型转换异常或找不到目标文档,触发500错误。

解决方案

1. 修正实体类主键配置

在Course类的id字段上添加@Id注解,将其指定为MongoDB的主键,替代默认的_id:

package com.springrest.springrest.entities;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;

@Document(collection="Course")
public class Course {

    @Id
    @Field( name="id")
    private int id;
    
    @Field(name="title")
    private String title;
    
    @Field(name="description")
    private String description;
    
    // 构造方法、getter/setter、toString 保持不变
}

2. 修复Service层更新逻辑

  • 避免直接调用Optional.get()(找不到文档时会抛出NoSuchElementException),先判断文档是否存在
  • 不要修改主键id(避免因请求体与路径ID不一致导致创建新文档)
@Override
public Course updateCourse(int courseId, Course course) {
    Optional<Course> optionalCourse = this.userlist.findById(courseId);
    if (optionalCourse.isPresent()) {
        Course existingCourse = optionalCourse.get();
        existingCourse.setTitle(course.getTitle());
        existingCourse.setDescription(course.getDescription());
        return this.userlist.save(existingCourse);
    } else {
        throw new RuntimeException("课程不存在,ID:" + courseId);
    }
}

3. 优化Controller层删除方法

  • 捕获异常,返回友好的响应状态码
  • 先校验文档是否存在,避免无效操作
@DeleteMapping("/courses/{courseId}")
public ResponseEntity<?> deleteCourse(@PathVariable String courseId) {
    try {
        int id = Integer.parseInt(courseId);
        if (this.courseService.getCourse(id).isPresent()) {
            this.courseService.deleteCourse(id);
            return ResponseEntity.ok("课程删除成功");
        } else {
            return ResponseEntity.notFound().build();
        }
    } catch (NumberFormatException e) {
        return ResponseEntity.badRequest().body("无效的课程ID格式");
    } catch (Exception e) {
        return ResponseEntity.internalServerError().body("删除失败:" + e.getMessage());
    }
}

4. 确保Repository泛型正确

确认CourseRepository继承MongoRepository<Course, Integer>,主键类型与实体类一致:

public interface CourseRepository extends MongoRepository<Course, Integer> {
}

关键说明

  • MongoDB中,save()方法的行为由主键决定:主键存在则更新,不存在则插入
  • 永远不要直接调用Optional.get(),必须先通过isPresent()或ifPresent()判断是否存在,避免空指针异常
  • 路径变量中的ID应作为更新/删除的唯一依据,不要用请求体中的ID覆盖,避免数据混乱

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 02:05:16