求助解决Hibernate MultipleBagFetchException异常,无法访问jsondoc
MultipleBagFetchException异常问题 嘿,我来帮你搞定这个头疼的Hibernate异常!这个错误的核心原因很明确:Hibernate不允许同时用FetchType.EAGER加载多个Bag类型的集合(也就是你代码里的List集合,默认情况下Hibernate会把List当作Bag处理——无序、允许重复元素)。同时加载多个Bag会导致严重的笛卡尔积问题,数据重复不说,性能也会崩,所以Hibernate直接阻止了这种操作。
给你几个实用的解决方案,你可以根据自己的业务场景选:
方案1:把其中一个(或多个)List改成Set集合
Set是无序且不允许重复的集合类型,Hibernate支持同时用FetchType.EAGER加载多个Set。只需要修改实体类里的集合定义就行:
原来的代码:
@OneToMany(fetch = FetchType.EAGER, mappedBy = "applicant") private List<PhoneApplicant> phoneApplicant; @OneToMany(fetch = FetchType.EAGER, mappedBy = "applicant") private List<AddressApplicant> addressApplicant;
改成Set版本:
@OneToMany(fetch = FetchType.EAGER, mappedBy = "applicant") private Set<PhoneApplicant> phoneApplicant; @OneToMany(fetch = FetchType.EAGER, mappedBy = "applicant") private List<AddressApplicant> addressApplicant; // 或者两个都改成Set也行
注意:如果业务逻辑允许集合元素重复,那Set可能不适用,这时候换其他方案。
方案2:改用懒加载+手动关联查询
如果必须保留List集合,可以把FetchType改成LAZY(这其实也是Hibernate的默认值),然后在需要加载关联集合的时候,用JPQL或者原生SQL手动写JOIN FETCH查询,精准控制加载哪些集合:
比如在你的Spring Data JPA Repository里定义查询方法:
@Query("SELECT a FROM Applicant a JOIN FETCH a.phoneApplicant JOIN FETCH a.addressApplicant WHERE a.id = :id") Applicant findByIdWithAllRelations(@Param("id") Long id);
这样查询的时候会一次性加载Applicant和它的两个关联集合,不会触发异常。
方案3:用@Fetch(FetchMode.SUBSELECT)注解优化加载方式
给其中一个或多个List集合加上@Fetch(FetchMode.SUBSELECT),Hibernate会用子查询的方式加载集合,而不是直接JOIN,这样就能避免笛卡尔积问题,同时也能保留List类型和EAGER加载:
@OneToMany(fetch = FetchType.EAGER, mappedBy = "applicant") @Fetch(FetchMode.SUBSELECT) private List<PhoneApplicant> phoneApplicant; @OneToMany(fetch = FetchType.EAGER, mappedBy = "applicant") private List<AddressApplicant> addressApplicant;
这个方案适合那些必须同时加载多个List集合,又不想改集合类型的场景。
方案4:开启Open Session in View(谨慎使用)
如果是Web项目,可以考虑开启Open Session in View(OSIV)机制——简单说就是让Hibernate Session在视图渲染完成后再关闭,这样当你在前端访问集合属性时,Hibernate会自动懒加载数据。不过要注意:
- 这可能导致N+1查询问题,影响性能
- 高并发场景下有Session泄漏的风险,所以只适合小型项目或者非核心业务场景
你可以先试试方案1或者方案2,这两个是最常用也最稳妥的解决方式。如果之前试过某些方案没生效,可能是没改对地方——比如检查一下实体类的注解有没有写错,或者Repository的查询有没有覆盖默认的加载逻辑。
内容的提问来源于stack exchange,提问作者Alphonse

