Hibernate ManyToMany关联删除Gestionar报ObjectDeletedException 需保留Incidencia实体
问题根因
你碰到的这个异常,和“删除Gestionar是否会连带删除Incidencia”其实是两个独立的问题:
- 报错本身是双向关联的引用没拆干净导致的:你调用删除逻辑把Gestionar标记为删除状态了,但关联的Usuario实体持有的Gestionar集合里,还留着这个实例的引用。等事务提交时Hibernate刷缓存遍历整个对象图,顺着关联路径又碰到了这个已经被标记删除的Gestionar,触发了级联的saveOrUpdate逻辑,就会抛出“被删除的对象会被级联重新保存”的异常。
- 你最初担心的“删Gestionar带删Incidencia”,本质是关联配置了过宽的REMOVE级联,只要把这个配置去掉,删Gestionar的操作完全不会触碰Incidencia本身的记录。
具体调整方案
1. 校准实体关联的级联配置
按照你用Gestionar做中间实体、实现Usuario和Incidencia多对多关联的结构,逐个核对所有关联的级联配置:
- Gestionar实体内的两个
@ManyToOne字段:- 关联Usuario的字段:去掉所有多余级联配置,默认无任何级联即可,绝对不要加
cascade = CascadeType.ALL - 关联Incidencia的字段:务必删除配置中的
CascadeType.REMOVE,正确的配置参考如下:
只要没有REMOVE级联,删除Gestionar时只会清掉中间表的关联记录,Incidencia本身的记录完全不会被改动,天然满足你的需求。@ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "incidencia_id") private Incidencia incidencia;
- 关联Usuario的字段:去掉所有多余级联配置,默认无任何级联即可,绝对不要加
- Usuario实体内关联Gestionar的集合字段:
- 删掉原本的
cascade = CascadeType.ALL全量级联,只保留业务必需的PERSIST、MERGE级联 - 加上
mappedBy = "usuario"标记当前为关联的反向端,由Gestionar端的外键维护关联关系,避免双向关联的外键重复维护问题 - 不要在这个集合的级联配置里加
REMOVE类型,否则删除Usuario时会自动级联删掉所有关联的Gestionar,这个逻辑要根据你的业务需求单独评估
- 删掉原本的
2. 补齐删除操作的关联维护逻辑
很多人只改配置不做引用摘除,最终还是会触发同类报错:
- 执行
session.remove(gestionar实例)之前,必须先把这个要删除的Gestionar,从关联的Usuario持有的Gestionar集合中手动移除 - 整个流程不需要对Incidencia实体做任何额外操作
- 如果你的删除流程是连带删除Usuario名下的所有Gestionar,不要依赖自动级联删除,要遍历Usuario持有的Gestionar集合,逐个将实例从集合中移除后再执行remove,避免触发对象图的级联回写
常见踩坑提醒
- 不要为了消错随便在关联字段上加
@JsonIgnore、@ToString.Exclude,这类注解只影响序列化和日志打印逻辑,Hibernate遍历对象图时不会识别这些标记,根本解决不了级联回写的问题 - 如果Gestionar是联合主键结构,要确保删除时拿到的是持久态的Gestionar实例,不要拿临时构造的游离态实例直接remove,否则也会触发关联匹配失败的异常
内容的提问来源于stack exchange,提问作者codeNightmare
相关产品推荐
相关产品推荐

