如何解决Hibernate的Found shared references to a collection异常
问题分析与解决方法
问题本质
你遇到的org.hibernate.HibernateException: Found shared references to a collection异常,核心原因是BeanUtils.copyProperties做的是浅拷贝:对于集合类型的属性(比如你代码里的implementos),它只会复制集合的内存引用,不会创建新的集合实例。这就导致entity和entityNew两个对象共享同一个集合对象,而Hibernate不允许两个持久化/待持久化的实体关联同一个集合实例,否则会破坏其状态追踪机制。
解决办法
1. 手动重写集合引用(最简单直接)
在BeanUtils拷贝之后,手动为新实体创建独立的集合实例,把原集合的元素复制进去:
MyObj entity = this.search(id); MyObj entityNew = new MyObj(); BeanUtils.copyProperties(entity, entityNew, "id"); // 关键:创建新的集合实例,避免共享引用 entityNew.setImplementos(new ArrayList<>(entity.getImplementos())); // 如果还有其他集合字段,同样处理 // entityNew.setOutraColecao(new HashSet<>(entity.getOutraColecao()));
注意:如果原集合是Hibernate的代理集合(比如PersistentBag),直接用ArrayList包装就能转换成普通Java集合,脱离Hibernate的代理追踪。
2. 使用支持深拷贝的工具类
如果实体有很多集合字段,手动处理太繁琐,可以用支持深拷贝的工具:
- ModelMapper:配置深拷贝规则,自动处理集合:
ModelMapper modelMapper = new ModelMapper(); // 配置集合深拷贝 modelMapper.getConfiguration().setCollectionModelMapper(new CollectionModelMapper() { @Override public <T extends Collection<?>> T map(Collection<?> source, MappingContext context) { if (source == null) return null; Collection<Object> target = new ArrayList<>(); for (Object item : source) { target.add(modelMapper.map(item, item.getClass())); } return (T) target; } }); MyObj entityNew = modelMapper.map(entity, MyObj.class); // 手动清空id entityNew.setId(null); - Apache Commons Lang SerializationUtils(需实体实现Serializable):
MyObj entityNew = SerializationUtils.clone(entity); entityNew.setId(null);
3. 自定义拷贝构造方法
在实体类里写一个拷贝构造方法,专门处理集合的深拷贝:
public class MyObj { // ... 其他字段和方法 public MyObj(MyObj source) { this.nome = source.getNome(); this.descricao = source.getDescricao(); // 集合字段创建新实例 this.implementos = new ArrayList<>(source.getImplementos()); // 其他非集合字段逐个拷贝 } }
使用时直接调用:
MyObj entity = this.search(id); MyObj entityNew = new MyObj(entity); entityNew.setId(null);
注意事项
- 不要直接修改原集合后让新实体共享,即使你觉得逻辑上没问题,Hibernate的持久化上下文会把集合和实体绑定,共享会导致状态冲突。
- 对于关联的实体对象,如果也需要独立(比如集合里的元素也是持久化对象),可能需要递归拷贝,但大部分场景下,集合里的元素只需要复制引用(因为它们是数据库中已存在的记录),除非你要创建新的关联实体。
内容的提问来源于stack exchange,提问作者danielfss
相关产品推荐
相关产品推荐

