Spring JPA单向OneToOne无级联配置保存时报detached entity错误如何解决
错误触发原因
你触发该错误的核心原因是:
- 调用
personRepository.save(person)时,若当前没有开启事务,方法执行完成后EntityManager会立即关闭,返回的person对象会进入*脱管(detached)*状态,不再被持久化上下文管理。 - Patient实体的
@OneToOne注解默认没有配置任何级联操作策略,当你保存关联了脱管Person对象的Patient时,Hibernate无法处理脱管的关联实体,直接抛出detached entity passed to persist异常。
解决方案
以下三个方案任选其一即可:
- 方案1:将保存逻辑纳入同一个事务(最推荐)
在执行这段保存代码的方法上添加@Transactional注解(注意导入Spring的事务注解包org.springframework.transaction.annotation.Transactional),让整个操作在同一个持久化上下文中完成,save后的Person会保持托管状态,不会触发脱管问题。
代码示例:@Transactional public void demo() { Person person = new Person("patient", "pat", "patient@email.com"); personRepository.save(person); Patient patient1 = new Patient(person); patientRepository.save(patient1); } - 方案2:为OneToOne关联添加级联合并策略
修改Patient类的@OneToOne注解,添加级联合并配置,让Hibernate保存Patient时自动将脱管的Person合并到当前持久化上下文:
若业务需要也可以直接配置@OneToOne(cascade = CascadeType.MERGE) @MapsId @JoinColumn(name = "user_id") private Person person;cascade = CascadeType.ALL适配更多场景。 - 方案3:保存Patient前重新查询托管状态的Person
保存Patient前用Person的id从数据库重新查询一次,拿到当前持久化上下文管理的Person对象再关联,仅适合不方便修改事务和实体配置的场景:Person person = new Person("patient", "pat", "patient@email.com"); person = personRepository.save(person); // 重新查询获取托管对象 Person managedPerson = personRepository.findById(person.getUserId()).get(); Patient patient1 = new Patient(managedPerson); patientRepository.save(patient1);
内容的提问来源于stack exchange,提问作者Hzt
相关产品推荐
相关产品推荐

