Spring Data JPA @OneToMany映射保存时出现StackOverflowError求助
问题描述
我正在学习Spring Boot,有GYMS和HOURS两张数据表,在Gym实体中声明了@OneToMany映射,Hours实体中声明了@ManyToOne映射,但保存新健身房及其营业时间到数据库时出现StackOverflowError,求解决办法,谢谢!
数据表结构
CREATE TABLE gyms ( id int NOT NULL AUTO_INCREMENT, name varchar(60) NOT NULL, address varchar(255), city varchar(255), province varchar(3), postal_code char (7), phone_number varchar(20), PRIMARY KEY (id) ); CREATE TABLE hours ( id int NOT NULL AUTO_INCREMENT, gym_id int NOT NULL, day_of_week INT, opening_time TIME, closing_time TIME, PRIMARY KEY (id), FOREIGN KEY (gym_id) REFERENCES gyms(id) );
Gym实体类
@Entity @Table (name = "gyms") @NoArgsConstructor @Getter @Setter public class Gym { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; private String name; private String address; private String city; private String province; private String postalCode; private String phoneNumber; @OneToMany(mappedBy = "gym", cascade = CascadeType.ALL) private List<Hours> hours; public Gym(String name, String address, String city, String province, String postalCode, String phoneNumber) { this.name = name; this.address = address; this.city = city; this.province = province; this.postalCode = postalCode; this.phoneNumber = phoneNumber; } }
Hours实体类
@Entity @Table (name = "hours") @NoArgsConstructor @Getter @Setter public class Hours { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "gym_id") private Gym gym; private int dayOfWeek; private Time openingTime; private Time closingTime; public Hours(int dayOfWeek, String openingTime, String closingTime) { this.dayOfWeek = dayOfWeek; this.openingTime = Time.valueOf(openingTime); this.closingTime = Time.valueOf(closingTime); } }
GymService类
@Service public class GymService { private final GymRepository gymRepository; private final HoursRepository hoursRepository; @Autowired public GymService(GymRepository gymRepository, HoursRepository hoursRepository) { this.gymRepository = gymRepository; this.hoursRepository = hoursRepository; } public Gym addNewGym(Gym gym, List<Hours> hours) { gym.setHours(hours); for (Hours hour : hours) { hour.setGym(gym); } return gymRepository.save(gym); } }
问题原因及解决方案
出现StackOverflowError的核心原因是双向关联实体间的循环引用:Lombok默认生成的toString()(部分IDE或Lombok配置会自动添加)会包含关联字段,导致调用Gym.toString()时遍历hours列表,每个Hours.toString()又会调用关联的Gym.toString(),无限循环直到栈溢出。
解决步骤:
排除关联字段的toString生成
在实体类上添加@ToString注解,明确排除互相引用的字段:// Gym类修改 @Entity @Table(name = "gyms") @NoArgsConstructor @Getter @Setter @ToString(exclude = "hours") public class Gym { // 原有代码不变 }// Hours类修改 @Entity @Table(name = "hours") @NoArgsConstructor @Getter @Setter @ToString(exclude = "gym") public class Hours { // 原有代码不变 }同步处理equals和hashCode
若Lombok自动生成了equals/hashCode方法,同样需要排除关联字段避免循环:// Gym类添加 @EqualsAndHashCode(exclude = "hours") // Hours类添加 @EqualsAndHashCode(exclude = "gym")验证保存逻辑
你的GymService保存逻辑是正确的:双向关联关系已正确建立,CascadeType.ALL能实现级联保存,无需修改。
额外建议
- 双向关联中
@OneToMany使用mappedBy是正确做法,避免双向维护外键导致数据不一致; @ManyToOne上的FetchType.LAZY是默认值,显式声明有助于提升查询性能,避免不必要的关联数据加载。
内容的提问来源于stack exchange,提问作者developerron
相关产品推荐
相关产品推荐

