Hibernate JPA查询出现重复子元素结果?技术咨询
嘿,这个问题我之前做电商项目用JPA关联的时候也踩过坑!来帮你捋捋原因和解决办法:
最核心的坑:复合主键类没写对equals()和hashCode()
你的OrderedItem用了@IdClass(OrderedItemPK.class)复合主键,而JPA(比如Hibernate)判断两个实体是不是同一个,全靠equals()和hashCode()方法。如果:
OrderedItemPK压根没实现这俩方法,或者- 实现的时候没用到所有主键字段
那Hibernate处理查询结果时,会把逻辑上完全一样的OrderedItem当成不同的对象,最后就会在items集合里出现重复项。
解决办法:给OrderedItemPK补全正确的equals和hashCode
复合主键类必须实现Serializable,而且equals/hashCode得基于所有主键字段来写。比如假设你的OrderedItemPK包含customerId和productId两个主键字段:
public class OrderedItemPK implements Serializable { // 对应Customer表的id字段 private int customerId; // 假设另一个主键是商品ID private int productId; // 别忘了写这两个字段的getter和setter @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; OrderedItemPK that = (OrderedItemPK) o; return customerId == that.customerId && productId == that.productId; } @Override public int hashCode() { return Objects.hash(customerId, productId); } }
另一个可能:EAGER抓取导致的左连接结果重复
你给@OneToMany设了fetch=FetchType.EAGER,Hibernate会自动用左连接查询Customer和它的OrderedItem,这时候数据库返回的结果集里,同一个Customer会对应多行(每个OrderedItem一行)。如果Hibernate组装集合时没正确去重,也会出重复。
解决办法:用DISTINCT优化JPQL查询
如果是用JPQL查的话,加个DISTINCT关键字就能让Hibernate自动去重:
SELECT DISTINCT c FROM Customer c JOIN FETCH c.items
这样Hibernate就能识别出重复的OrderedItem,不会重复加到集合里。
额外小建议:考虑把FetchType改成LAZY
EAGER抓取虽然能立刻加载关联数据,但容易带来性能问题和这类重复bug。如果业务允许,改成fetch=FetchType.LAZY,然后在需要加载关联数据的时候,用JOIN FETCH主动触发关联查询,这样更灵活也更可控。
最后再检查下OrderedItem里的@ManyToOne配置对不对,确保关联的是Customer的id字段:
@Id @ManyToOne @JoinColumn(name = "customer_id", referencedColumnName = "id") private Customer customer;
内容的提问来源于stack exchange,提问作者Mideel

