查询数据库Wishlist对象时触发StackOverflowError的解决求助
问题:Spring Boot+JPA查询心愿单商品时触发StackOverflowError
在Spring Boot+JPA项目中,通过商品ID检查商品是否存在于心愿单时,调用仓库查询方法触发了StackOverflowError,相关代码及报错信息如下:
实体类代码
@Entity @Data @Table(name = "wishlist") public class Wishlist { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; @OneToOne(targetEntity = Customer.class, fetch = FetchType.EAGER) @JoinColumn(nullable = false,name = "customer_id") private Customer customer; @Column(name = "created_date") private Date createdDate; @ManyToOne @JoinColumn(name = "product_id") private Products product; public Wishlist(Customer customer, Products product) { this.customer = customer; this.createdDate = new Date(); this.product = product; } public Wishlist() { } }
仓库接口代码
public interface WishlistRepository extends JpaRepository<Wishlist, Integer> { List<Wishlist> findAllByCustomerIdOrderByCreatedDateDesc(Integer customerId); Optional<Wishlist> findByProductId(Integer productId); }
服务层代码
@Service @Transactional public class WishlistServiceImpl implements WishlistService{ @Autowired WishlistRepository wishlistRepo; @Override public void createWishlist(Wishlist wishlist,Integer productId) throws ProductNotExistsException { Optional<Wishlist> optionalProduct = wishlistRepo.findByProductId(productId); System.out.println(optionalProduct); } }
报错信息
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.StackOverflowError] with root cause java.lang.StackOverflowError: null at java.base/java.lang.AbstractStringBuilder.putStringAt(AbstractStringBuilder.java:1720) ~[na:na] at java.base/java.lang.AbstractStringBuilder.putStringAt(AbstractStringBuilder.java:1724) ~[na:na] at java.base/java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:583) ~[na:na] at java.base/java.lang.StringBuilder.append(StringBuilder.java:175) ~[na:na] at java.base/java.lang.StringBuilder.append(StringBuilder.java:87) ~[na:na] at java.base/java.lang.AbstractStringBuilder.<init>(AbstractStringBuilder.java:112) ~[na:na] at java.base/java.lang.StringBuilder.<init>(StringBuilder.java:127) ~[na:na] at com.ecommerce.entity.Customer.toString(Customer.java:29) ~[classes/:na]
问题原因及解决方法
原因
报错栈显示问题出在Customer类的toString方法,结合代码中使用了Lombok的@Data注解,核心原因是实体类之间的双向引用导致toString方法递归调用:
Wishlist类的@Data注解会自动生成包含customer属性的toString方法;Customer类大概率也用了@Data或自定义了包含wishlist(或关联心愿单集合)的toString方法;- 执行
System.out.println(optionalProduct)时,会触发Wishlist的toString,进而调用Customer的toString,而Customer的toString又会反向调用Wishlist的toString,无限递归最终导致栈溢出。
解决方法
修改Lombok注解,排除双向引用属性
将Wishlist类的@Data替换为@Getter+@Setter+@ToString(exclude = "customer"),避免toString方法包含会触发循环的customer属性;同时检查Customer类,如果它关联了Wishlist,也要在其toString中排除对应属性,比如@ToString(exclude = "wishlist")。修改后的
Wishlist示例:@Entity @Getter @Setter @ToString(exclude = "customer") @Table(name = "wishlist") public class Wishlist { // 原有属性和方法保持不变 }避免直接打印整个实体对象
如果只需要判断商品是否存在,直接打印判断结果即可,无需输出整个实体:System.out.println("商品是否在心愿单中:" + optionalProduct.isPresent()); // 或仅打印关键属性 optionalProduct.ifPresent(w -> System.out.println("心愿单记录ID:" + w.getId()));清理不必要的双向关联
检查Customer类中是否存在@OneToOne(mappedBy = "customer")的Wishlist属性,如果业务上不需要双向关联,直接删除该属性,从根源避免循环引用问题。
内容的提问来源于stack exchange,提问作者Pritam Das
相关产品推荐
相关产品推荐

