You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hibernate更新对象时关联实体重复问题求助

问题描述

我有Goods和Sizes两张表,多个Size可关联同一个Good,接口返回的JSON结构如下:

{    
  "id": 11,    
  "title": "Model2",    
  "sex": "WOMAN",    
  "manufacturer": {      
    "id": 1,      
    "manufacturerName": "Ralf",      
    "address": "Moscow",      
    "telephone": "9-999-999-99-99"    
  },    
  "manufacturerId": 1,    
  "sizes": [      
    {        
      "size": 35,        
      "quantity": 5      
    },      
    {        
      "size": 46,        
      "quantity": 4      
    }    
  ]  
}

当我尝试更新某个Good(比如添加或删除一个Size)时,所有Size都会重复,原本2个会变成4个:

"sizes": [      
  {        
    "size": 30,        
    "quantity": 2      
  },      
  {        
    "size": 42,        
    "quantity": 5      
  },      
  {        
    "size": 41,        
    "quantity": 2      
  },      
  {        
    "size": 42,        
    "quantity": 5      
  }
]

我的更新方法如下:

@Override    
public void saveGood(Good good) {        
    Session session = entityManager.unwrap(Session.class);        
    System.out.println(good);        
    session.merge(good); //SaveOrUpdate substitute    
}

REST控制器路由:

@PatchMapping("/goods")    
public Good updateGood(@RequestBody Good good) {        
    goodService.saveGood(good);        
    return good;    
}

实体类关联配置:
Good类:

@JsonManagedReference    
@OneToMany(cascade = CascadeType.ALL, mappedBy = "good")//Uni-directional reference to size array    
List<Size> sizes; 

Size类:

@Column(name = "goodid", insertable = false, updatable = false) //Check else    
private int goodId;    
@JsonBackReference    
@ManyToOne(cascade = CascadeType.ALL)    
@JoinColumn(name = "goodId")    
Good good;

请问如何解决更新时关联Size实体重复的问题?


解决方案

1. 先清理旧关联,再替换为新数据

使用merge时,Hibernate会保留数据库中已存在的关联对象,同时添加传入的新对象,导致重复。需要先从数据库加载持久化状态的Good,清空现有Size关联后,再添加新的Size并维护双向关系:

@Override    
public void saveGood(Good good) {        
    Session session = entityManager.unwrap(Session.class);        
    // 加载数据库中当前的Good对象
    Good persistedGood = session.get(Good.class, good.getId());
    
    // 清空现有Size关联
    persistedGood.getSizes().clear();
    
    // 绑定新Size与持久化Good的双向关系
    for (Size size : good.getSizes()) {
        size.setGood(persistedGood);
        persistedGood.getSizes().add(size);
    }
    
    session.merge(persistedGood);    
}

2. 调整级联策略,避免过度级联

当前@OneToMany和@ManyToOne都设置了CascadeType.ALL,会导致更新Good时所有关联Size被无差别级联操作。如果Size生命周期完全依赖Good,可保留核心级联类型,否则调整为:
Good类修改:

@JsonManagedReference    
@OneToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, mappedBy = "good")    
List<Size> sizes; 

Size类修改:

@JsonBackReference    
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})    
@JoinColumn(name = "goodId")    
Good good;

3. 给Size添加唯一约束

在数据库层面,同一个Good下的尺码应该唯一,通过实体类注解添加组合唯一约束,从根源阻止重复数据:

@Entity
@Table(uniqueConstraints = {@UniqueConstraint(columnNames = {"goodId", "size"})})
public class Size {
    // 其他字段定义
}

4. 严格维护双向关联关系

双向关联中,必须确保Size的good属性指向持久化状态的Good对象,而非传入的临时对象,否则Hibernate无法识别关联关系,会误判为新对象插入。

内容的提问来源于stack exchange,提问作者velovatik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 13:20:28