Spring JPA关联表字段查询报错:派生查询触发StackOverflowError
问题解决:JPA查询栈溢出及关联字段查询方案
问题分析
你遇到的StackOverflowError并非查询方法命名错误——findDiscountContractByExtReferenceIdAndContractTypeType本身符合Spring Data JPA的命名规则,能正确生成查询语句。错误根源是@Data注解自动生成的toString方法:
DiscountContract包含懒加载的ContractType关联字段,当Optional调用DiscountContract的toString时,会触发懒加载代理对象的初始化;@Data生成的toString会递归打印关联对象的所有字段,Hibernate代理对象的toString逻辑间接触发了对DiscountContract的引用,形成无限递归,最终导致栈溢出。
解决方案
1. 修复栈溢出问题
在DiscountContract的contractType字段上添加@ToString.Exclude,避免toString递归调用关联对象:
@Data @Entity @Builder @NoArgsConstructor @AllArgsConstructor public class DiscountContract { @Id @GeneratedValue(strategy = GenerationType.AUTO, generator = "native") @GenericGenerator(name = "native", strategy = "native") private Long id; private String extReferenceId; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "contract_type_id", nullable = false, referencedColumnName = "id") @ToString.Exclude // 排除该字段的toString递归 private ContractType contractType; }
也可在ContractType类中用@ToString.Exclude标记非必要字段,进一步降低递归风险。
2. SpEL查询实现(可选)
若偏好显式查询语句,可在Repository接口中添加@Query注解实现SpEL查询:
@Repository public interface DiscountContractRepository extends JpaRepository<DiscountContract, Long> { @Query("SELECT dc FROM DiscountContract dc JOIN dc.contractType ct " + "WHERE dc.extReferenceId = :extRefId AND ct.type = :type") Optional<DiscountContract> findByExtReferenceIdAndContractTypeType( @Param("extRefId") String extReferenceId, @Param("type") String type ); }
这种方式更直观,也能避免过长的方法命名。
验证说明
修复toString递归问题后,原方法命名查询即可正常运行;使用SpEL查询时,需确保参数名与@Param注解一致,避免参数绑定错误。
内容的提问来源于stack exchange,提问作者Tsvetoslav Tsvetkov
相关产品推荐
相关产品推荐

