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
相关产品推荐
相关产品推荐

