Hibernate出现Found shared references to a collection异常的解决咨询
问题根源
你遇到的异常核心原因有两点:
- 当前映射设计中,
Table1的code并非唯一字段,但你用它作为@OneToMany的关联键(referencedColumnName = "CODE"),导致多个Table1实例(ID1、ID2的code都是A)会关联到同一批Table2数据。 - Hibernate为了性能优化,会复用关联到同一批数据的集合实例,而Hibernate的规则要求每个实体实例的集合必须是独立的,共享集合就会在事务提交时触发该异常。
解决方案
1. 修正关联语义,改用双向关联(推荐)
当前的单向一对多映射不符合标准的一对多语义(子实体Table2应该只属于一个父实体Table1),改成双向关联可以明确每个Table2所属的Table1,从根源避免集合复用:
class Table1 { @Id private Long id; @Column(name = "CODE") private String code; // 由Table2的table1字段维护关联关系 @OneToMany(mappedBy = "table1") private List<Table2> table2List = new ArrayList<>(); } class Table2 { @Id private Long id; // 关联到Table1的主键ID,确保每个Table2只属于一个Table1 @ManyToOne @JoinColumn(name = "SOURCE", referencedColumnName = "ID") private Table1 table1; }
如果业务上必须用code关联,那需要先给Table1的code添加唯一约束,确保每个code对应唯一的Table1实例,再调整双向关联的referencedColumnName为CODE。
2. 强制Hibernate为每个实例创建独立集合
如果暂时无法修改数据模型,可通过查询或映射配置强制Hibernate为每个Table1实例单独加载集合:
- 方式一:查询时显式初始化集合
使用JOIN FETCH的HQL查询,让Hibernate在加载Table1时就为每个实例单独查询对应的Table2集合:List<Table1> table1List = entityManager.createQuery( "SELECT t1 FROM Table1 t1 JOIN FETCH t1.table2List", Table1.class ).getResultList(); - 方式二:修改映射注解
在@OneToMany中添加@Fetch(FetchMode.SELECT),强制Hibernate为每个Table1实例单独执行查询获取集合:class Table1 { @Id private Long id; @Column(name = "CODE") private String code; @OneToMany @JoinColumn(name = "SOURCE", referencedColumnName = "CODE") @Fetch(FetchMode.SELECT) private List<Table2> table2List = new ArrayList<>(); }
3. 临时规避方案(不推荐长期使用)
如果只是临时解决问题,可以在加载Table1实例后,手动为每个集合创建新的实例:
for (Table1 t1 : table1List) { t1.setTable2List(new ArrayList<>(t1.getTable2List())); }
这种方式会破坏Hibernate的懒加载机制,仅适合临时应急。
内容的提问来源于stack exchange,提问作者Okay Atalay
相关产品推荐
相关产品推荐

