Spring Boot中Lombok @Data注解致关联表查询为空问题求助
问题描述
我用Spring Boot + MySQL开发API时碰到个奇怪问题:关联表EtapeRecette.java用Lombok的@Data注解生成getter/setter,编译没问题,但调用RecetteRepository.findAll()返回的etapes数组是空的;换成手动写getter/setter或者用@Getter+@Setter注解就完全正常。想知道@Data失效的原因是什么?
附上三个实体类代码:
Recette.java
package org.microferme.charme.model; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import jakarta.persistence.*; import lombok.Data; import lombok.NoArgsConstructor; import java.sql.Timestamp; import java.util.Date; import java.util.Set; @Data @NoArgsConstructor @Entity @Table(name="Recette") public class Recette { @Id private String id; @Column(name = "nom") private String nom; @Column(name = "nb_personne") private int nbPersonne; @Column(name = "prix_par_personne") private float prixParPersonne; @OneToMany(mappedBy = "recette", cascade = CascadeType.ALL, orphanRemoval = true) @JsonIgnoreProperties("recette") private Set<MediaRecette> medias; @OneToMany(mappedBy = "recette", cascade = CascadeType.ALL, orphanRemoval = true) @JsonIgnoreProperties("recette") private Set<StockUtile> ingredients; @OneToMany(mappedBy = "recette", cascade = CascadeType.ALL, orphanRemoval = true) @JsonIgnoreProperties("recette") private Set<EtapeRecette> etapes; public Recette(String nom, int nbPersonne, float prixParPersonne) { //Si l'id n'est pas spécifié on prend la timestamp actuelle Date date = new Date(); this.id = String.valueOf(new Timestamp(date.getTime()).getTime()); this.nom = nom; this.nbPersonne = nbPersonne; this.prixParPersonne = prixParPersonne; } public void addMedia(MediaRecette media) { this.medias.add(media); } public void addIngredient(StockUtile ingredient) { this.ingredients.add(ingredient); } public void addEtape(EtapeRecette etapeRecette) { this.etapes.add(etapeRecette); } }
Etape.java
package org.microferme.charme.model; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import jakarta.persistence.*; import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; import java.util.Set; @Data @Entity @Table(name = "Etape") public class Etape { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; @Column(name = "ordre") private float ordre; @Column(name = "duree") private float duree; @Column(name = "description") private String description; @ManyToOne private Ustensile ustensile; public Etape() { } public Etape(float ordre, float duree, String description, Ustensile ustensile) { this.ordre = ordre; this.duree = duree; this.description = description; this.ustensile = ustensile; } }
EtapeRecette.java(Recette与Etape的关联表)
package org.microferme.charme.model; import jakarta.persistence.*; import lombok.Data; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import org.microferme.charme.model.embeddable.EtapeRecetteId; @Entity @Data @Table(name = "EtapeRecette") public class EtapeRecette { @EmbeddedId private EtapeRecetteId id; @ManyToOne(cascade = CascadeType.ALL) @MapsId("recetteId") private Recette recette; @ManyToOne(cascade = CascadeType.ALL) @MapsId("etapeId") private Etape etape; public EtapeRecette() { } public EtapeRecette(Recette recette, Etape etape) { this.id = new EtapeRecetteId(recette.getId(), etape.getId()); this.recette = recette; this.etape = etape; } }
原因分析
问题出在@Data注解的附加功能上:它除了生成getter/setter,还默认生成基于所有字段的equals()、hashCode()和toString()方法。
对于EtapeRecette这种带嵌入式ID和双向JPA关联的实体,自动生成的equals()和hashCode()会依赖recette和etape这两个关联对象。而JPA加载关联集合(比如Recette的etapes)时,会用这些方法来管理集合元素:
- 当JPA使用懒加载时,
recette或etape可能是未初始化的代理对象,此时调用它们的属性计算equals/hashCode会触发意外的加载行为,导致集合无法正确填充。 - 双向关联的循环引用也会让equals/hashCode的逻辑出现异常,最终表现为返回的
etapes集合为空。
而@Getter+@Setter只生成存取方法,不会自动生成equals/hashCode,JPA就能正常处理关联集合的加载。
解决方案
有两种可行的解决方式:
- 直接替换
@Data为@Getter+@Setter+@NoArgsConstructor(保持原有构造逻辑),只生成必要的存取方法,避免equals/hashCode带来的问题。 - 保留
@Data,但通过@EqualsAndHashCode注解指定只基于嵌入式ID生成equals/hashCode,避免依赖关联对象:
@Entity @Data @EqualsAndHashCode(onlyExplicitlyIncluded = true) @Table(name = "EtapeRecette") public class EtapeRecette { @EmbeddedId @EqualsAndHashCode.Include private EtapeRecetteId id; // 其余代码不变 }
内容的提问来源于stack exchange,提问作者kalash2K
相关产品推荐
相关产品推荐

