Spring Data JPA 3.0+中Embeddable内@ManyToOne的Join Fetch失效求助
Spring Boot 3.x中CrudRepository关联Join Fetch失效问题(仅@ManyToOne在Embeddable类时触发)
问题详情
- 从Spring Boot 2.7.10升级到3.0.0(3.0.5版本仍存在该问题)后,Join Fetch策略失效:直接使用EntityManager查询时关联加载正常,但通过CrudRepository查询时出现异常。
- 涉及两个双向
@OneToMany关联的实体,其中@ManyToOne注解定义在Embeddable类中。 - 升级前通过join fetch预加载关联可避免N+1查询,升级后关联未被预加载,访问关联属性时抛出
LazyInitializationException,生成的SQL也未包含关联表的Join操作。 - 仅当
@ManyToOne位于Embeddable类中时才会触发该问题。
简化代码示例
SellerEntity代码
@Entity public class SellerEntity { @EmbeddedId private SellerEntityPK id; // 其他业务属性 }
SellerEntityPK代码
@Embeddable public class SellerEntityPK implements Serializable { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "company_id") private CompanyEntity company; // 其他主键属性 }
CompanyEntity代码
@Entity public class CompanyEntity { @Id private Long id; @OneToMany(mappedBy = "id.company") private List<SellerEntity> sellers; // 其他业务属性 }
查询语句代码
public interface SellerRepository extends CrudRepository<SellerEntity, SellerEntityPK> { @Query("SELECT s FROM SellerEntity s JOIN FETCH s.id.company WHERE s.id.company.id = :companyId") List<SellerEntity> findByCompanyId(@Param("companyId") Long companyId); }
运行时代码
sellerRepository.findByCompanyId(1L).forEach(seller -> { // 此处访问关联属性会抛出异常 System.out.println(seller.getId().getCompany().getName()); });
SQL对比
升级后生成的SQL
SELECT s.* FROM seller s WHERE s.company_id = ?
升级前生成的SQL
SELECT s.*, c.* FROM seller s JOIN company c ON s.company_id = c.id WHERE s.company_id = ?
错误信息
org.hibernate.LazyInitializationException: could not initialize proxy [com.example.CompanyEntity#1] - no Session at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:176) at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:322) at org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor.intercept(ByteBuddyInterceptor.java:45) at org.hibernate.proxy.ProxyConfiguration$InterceptorDispatcher.intercept(ProxyConfiguration.java:95) at com.example.CompanyEntity$HibernateProxy$...(Unknown Source) at com.example.SellerService.printSellers(SellerService.java:25)
解决方案建议
- 明确指定查询关联路径:在CrudRepository的
@Query中确保join fetch路径完整指向Embeddable内的关联属性(如s.id.company),Hibernate 6对嵌入式属性的路径解析规则更严格,需避免简化写法。 - 临时切换FetchType为EAGER:在Embeddable类的
@ManyToOne上添加fetch = FetchType.EAGER强制预加载关联,注意这会增加查询开销,仅作为临时规避方案。 - 改用EntityManager执行查询:既然直接使用EntityManager功能正常,可在业务层封装EntityManager的查询逻辑,绕过CrudRepository的兼容问题。
- 提交官方bug反馈:该问题大概率是Spring Boot 3.x(对应Hibernate 6.x)的兼容性bug,可向Spring或Hibernate官方提交issue,附带复现代码推动修复。
内容的提问来源于stack exchange,提问作者Gwennaël LONVERT
相关产品推荐
相关产品推荐

