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

JPA实现多对多关联触发IdentifierGenerationException异常求助

问题原因
  • 你使用了数据库自增策略生成Course的主键,在首次持久化Course之前,Course的id为null
  • CourseKeyword使用@MapsId将复合主键的courseId、keywordId映射到关联的实体属性,Hibernate需要从关联的Course对象读取id填充复合主键时,因为Course还未持久化没有id,因此抛出该异常
  • 另外你创建CourseKeyword对象时未初始化复合主键类CourseKeywordKey的实例,该属性为null时Hibernate无法将映射的id值写入,也是触发报错的潜在原因
解决方案

1. 调整保存顺序

先将Course持久化拿到生成的id,再构造CourseKeyword关联关系。

2. 初始化复合主键实例

创建CourseKeyword对象时,显式初始化CourseKeywordKey属性。

3. 修改后的业务代码示例

@Override
public void addNewCourse(CourseCreateDto courseCreateDto) {
    Teacher teacher = teacherRepository.findById(courseCreateDto.getTeacherId())
            .orElseThrow(() -> new CustomServiceException(NO_TEACHER_FOUND));
    Course course = modelMapper.map(courseCreateDto, Course.class);
    course.setCourseStatus(CourseStatus.ACTIVE);
    course.setTeacher(teacher);
    course.setUniqueCode(generateCourseUniqueCode());

    if(courseCreateDto.getKeywords().isEmpty()) 
        throw new CustomServiceException("Course keyword list is empty!");

    // 第一步:先保存课程,拿到自增生成的id
    course = courseRepository.save(course);

    // 第二步:构造关联关系,此时course已经有id
    List<CourseKeyword> courseKeywordList = courseCreateDto.getKeywords()
            .stream()
            .map(key -> {
                Keyword keyword = keywordRepository.findKeywordsByKeyword(key.toLowerCase())
                        .orElseThrow(() -> new CustomServiceException(""));
                CourseKeyword courseKeyword = new CourseKeyword();
                // 必须先初始化复合主键对象
                courseKeyword.setCourseKeywordKey(new CourseKeywordKey());
                courseKeyword.setCourse(course);
                courseKeyword.setKeyword(keyword);
                // 也可手动赋值主键,兼容性更强
                // courseKeyword.getCourseKeywordKey().setCourseId(course.getId());
                // courseKeyword.getCourseKeywordKey().setKeywordId(keyword.getId());
                return courseKeyword;
            })
            .collect(Collectors.toList());

    course.getKeywords().addAll(courseKeywordList);
    // 第二次保存级联保存关联表数据
    courseRepository.save(course);
}
额外检查项
  • 确认Keyword对象从数据库查询返回时已存在合法id,不存在id为空的情况
  • 确认Course实体第一次调用save后,返回的对象已被正确赋值自增生成的id

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 21:36:04