使用Spring JPA的findAllByPropertyTitleContaining方法遇StackOverflowError
Spring Boot调用JPA findAllByPropertyTitleContaining触发StackOverflowError问题解决
问题描述
基于Spring Boot开发项目,使用Thymeleaf作为模板引擎。调用Spring JPA的findAllByPropertyTitleContaining方法时,触发了StackOverflowError错误。
相关代码
Property实体类
package com.example.estateagencyspring.models; import lombok.Data; import javax.persistence.*; import java.util.ArrayList; import java.util.List; @Entity @Data public class Property { @Id private String id; private String propertyTitle; private String propertyDescription; private String location; private String type; private String status; private String area; private String beds; private String baths; private String garage; private String defaultPicture; private String price; @Lob private String googleSrc; @OneToMany(mappedBy="property") private List<Picture> pictures = new ArrayList<>(); @ManyToMany(fetch = FetchType.LAZY) @JoinTable( name = "property_amenity", joinColumns = @JoinColumn(name = "property_id"), inverseJoinColumns = @JoinColumn(name = "amenity_id") ) private List<Amenity> amenities = new ArrayList<>(); }
Amenity实体类(与Property为ManyToMany关联)
import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.Id; import javax.persistence.ManyToMany; import java.util.ArrayList; import java.util.List; @Entity @Data public class Amenity { @Id private String id; private String name; @ManyToMany(mappedBy = "amenities", fetch = FetchType.LAZY) private List<Property> properties = new ArrayList<>(); }
PropertyRepository接口
public interface PropertyRepository extends JpaRepository<Property, String> { Optional<Property> findByPropertyTitle(String title); List<Property> findAllByPropertyTitleContaining(String title); }
PropertyService相关方法
... public List<Property> searchByTitle(String title){ System.out.println(propertyRepository.findAllByPropertyTitleContaining(title)); return propertyRepository.findAllByPropertyTitleContaining(title); }
原因分析
StackOverflowError的核心原因是双向ManyToMany关联引发的循环引用。你使用了Lombok的@Data注解,该注解会自动生成toString()、equals()、hashCode()方法。当执行System.out.println打印查询结果时,Property的toString()会遍历其amenities集合;而每个Amenity的toString()又会遍历自身的properties集合,如此往复形成无限循环,最终导致栈内存溢出。
解决方法
方法一:用Lombok注解排除循环字段
在双向关联的其中一方字段上添加@ToString.Exclude,避免toString()方法包含该关联集合:
- 示例:修改Property类的amenities字段
@ManyToMany(fetch = FetchType.LAZY) @JoinTable( name = "property_amenity", joinColumns = @JoinColumn(name = "property_id"), inverseJoinColumns = @JoinColumn(name = "amenity_id") ) @ToString.Exclude private List<Amenity> amenities = new ArrayList<>();
- 或者修改Amenity类的properties字段
@ManyToMany(mappedBy = "amenities", fetch = FetchType.LAZY) @ToString.Exclude private List<Property> properties = new ArrayList<>();
方法二:手动重写toString()方法
去掉@Data中的自动生成逻辑,手动编写toString()方法,只包含基本属性,不涉及双向关联的集合:
示例:在Property类中重写
@Override public String toString() { return "Property{" + "id='" + id + '\'' + ", propertyTitle='" + propertyTitle + '\'' + ", propertyDescription='" + propertyDescription + '\'' + ", location='" + location + '\'' + ", type='" + type + '\'' + ", status='" + status + '\'' + ", area='" + area + '\'' + ", beds='" + beds + '\'' + ", baths='" + baths + '\'' + ", garage='" + garage + '\'' + ", defaultPicture='" + defaultPicture + '\'' + ", price='" + price + '\'' + ", googleSrc='" + googleSrc + '\'' + '}'; }
方法三:替换@Data为更细粒度的Lombok注解
用@Getter、@Setter、@RequiredArgsConstructor等注解替代@Data,避免自动生成包含关联集合的toString()、equals()等方法:
@Entity @Getter @Setter @RequiredArgsConstructor public class Property { // 实体属性及关联字段不变 }
内容的提问来源于stack exchange,提问作者Oth Mane
相关产品推荐
相关产品推荐

