保存过程中的休眠选择和“级联过程中的刷新很危险”异常

时间:2019-05-15 09:42:15

标签: hibernate spring-boot jpa spring-data-jpa

作为一项新要求,我必须将记录校验和保存在数据库中。

我们有一个单独的校验和表,其中包含table_name,record_id,record_version,checksum和其他一些字段。 我们还有一个基础实体类,它使用@PostPersist@PostUpdate@PostLoad方法保存和读取校验和数据。

让我们假设以下基本示例:

我们有一个TeacherCourse和一个TeacherCourse实体。 Teacher实体具有addCourse方法:

public void addCourse(Long courseId) {
    JpaTeacherCourse tc = new JpaTeacherCourse();
    JpaCourse course = new JpaCourse();
    course.setId(courseId);
    tc.setCourse(course);
    tc.setTeacher(this);
    tc.setStartDate(new Date());
    courses.add(tc);
}

BaseEntity方法的@PostLoad中,我们使用查询加载最新的校验和数据:

@Query(value = "SELECT * FROM checksums c WHERE c.table_name = :tableName AND c.record_id = :recordId ORDER BY id DESC LIMIT 1", nativeQuery = true)

问题在于,在保存Teacher实体的过程中,Hibernate加载了适当的过程,并触发了@PostLoad方法。 @PostLoad中的选择触发Hibernate刷新数据,最终结果是Flush during cascade is dangerous异常。

我想这是因为Hibernate没有引用课程实体。如果我将addCourse方法修改为此:

public void addCourse(Long courseId) {
    JpaTeacherCourse tc = new JpaTeacherCourse();
    CourseRepository repo = BeanUtil.getBean(CourseRepository.class);
    Optional<JpaCourse> courseOpt = repo.findById(courseId);
    JpaCourse course = courseOpt.get();
    tc.setCourse(course);
    tc.setTeacher(this);
    tc.setStartDate(new Date());
    courses.add(tc);
}

在这种情况下,在save方法期间不会触发选择,并且保存实体可以正常工作。

此解决方案的我的问题是,实体依赖于存储库,而这似乎不是最佳解决方案。

如果addCourse方法将实体作为参数,则可能是另一种选择,但是它需要在其他地方进行大量代码更改,并且还可以添加没有真正的Hibernate引用作为参数的实体,这就是再次是原始问题。

所以我的问题是如何正确解决此问题?

该项目基于Spring Boot 2.1并使用Hibernate 5.3

0 个答案:

没有答案