Hibernate级联保存异常求助:预约数据保存后被置空
我是Hibernate新手,正在尝试使用其级联功能。业务场景为门店(Store)与预约(Appointment)的一对多关联,一个门店拥有多个预约,每个预约仅关联一个门店。
实体类定义
@Entity @Table(name = "stores") class Store( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long? = null, @Version var version: Long = 0, @OneToMany(mappedBy = "store", cascade = [CascadeType.PERSIST,CascadeType.REMOVE]) var appointments: MutableList<Appointment> = mutableListOf(), ); @Entity @Table(name = "appointments") class Appointment( @ManyToOne(cascade = [CascadeType.PERSIST]) var store: Store, @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long? = null, @Version var version: Long = 0 )
服务方法代码
fun bookAppointment(newAppointment: NewAppointment): Appointment { Validators.validateEmail(newAppointment.customer.email) val store = storeRepository.findById(newAppointment.storeId).orElseThrow { EntityNotFoundException(Store::class.java) } val appointment = store.addAppointment(newAppointment) storeRepository.save(store) emailService.sendAppointmentBookedEmail(appointment) return appointment }
异常现象
执行save后出现异常:调试时可见预约已被添加到集合且值合法,但save调用后,Store实例及其预约集合中的原预约数据全部被置为null或0,最终存入数据库的数据错误。
双向关联未完整维护
你在store.addAppointment方法里仅将Appointment加入Store的集合,但未给Appointment的store属性赋值当前Store实例。Hibernate双向关联要求双方都维护关联关系,否则持久化时会出现数据不一致,甚至原有数据被覆盖置空。级联配置冲突
Appointment的@ManyToOne上配置了CascadeType.PERSIST,这会导致保存Appointment时级联保存Store,但Store本身是从数据库加载的托管实例,重复持久化会引发状态冲突。应去掉Appointment上的该级联配置,因为Store已是存在的实体,无需通过Appointment级联保存。addAppointment实现存在疏漏
检查store.addAppointment方法,正确实现需同时维护双向关联:fun addAppointment(newAppointment: NewAppointment): Appointment { val appointment = Appointment(/* 初始化其他必要属性 */) appointment.store = this // 关键:设置反向关联指向当前Store this.appointments.add(appointment) return appointment }冗余的save操作
Store是通过findById加载的托管实例,在Spring Data JPA的事务上下文内,托管实体的修改会被Hibernate自动同步到数据库,无需手动调用storeRepository.save(store)。手动调用可能触发不必要的状态刷新,导致数据异常。
内容的提问来源于stack exchange,提问作者Barracuda

