【Java 异常 & 解决方法 · JPA & lombok】java.lang.StackOverflowError 多对多 (manyToMany) 造成死循环

博客讨论了在Java项目中使用JPA和Lombok进行多对多关系映射时遇到的死循环问题。由于@Data注解生成的toString()方法,导致对象相互引用造成栈溢出。解决方案是使用@Getter@Setter替换@Data,或者在维护关系的一方使用@JsonIgnore注解,并重写toString()方法避免循环引用。示例代码展示了在Mask和Authority实体类中的具体修复措施。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、问题描述

在项目中同时使用JPA、lombok,对实体类配置多对多操作:

@Data	//错误根源
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "mask_tab")
public class Mask {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "mask_id")
    private Integer id;
    @Column(name = "mask_name")
    private String name;


    //多对多关系映射
    @ManyToMany(cascade=CascadeType.REFRESH,fetch = FetchType.EAGER)
    @JoinTable(name="mask_authority_tab", //中间表的名称
            //中间表 ma_mask_id 字段关联 mask_authority_tab 表的主键字段 mask_id
            joinColumns={@JoinColumn(name="ma_mask_id",referencedColumnName="mask_id")},
            //中间表 ma_mask_id 的字段关联 authority_tab 表的主键 authority_id
            inverseJoinColumns={@JoinColumn(name="ma_authority_id",referencedColumnName="authority_id")})
    private Set<Authority> authorities = new HashSet<>(0);
}
@Data	//错误根源
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "authority_tab")
public class Authority {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "authority_id")
    private Integer id;
    @Column(name = "authority_name")
    private String name;

    //多对多关系映射
    @ManyToMany(cascade=CascadeType.REFRESH,mappedBy="authorities")
    private Set<Mask> masks = new HashSet<>(0);
}

产生错误:

二、原因

使用lombak的 @Data ,在toString()方法中产生死循环

三、解决方法

使用lombak的 @Getter@Setter 等注解替换 @Data,或:

  • 重写 被维护类 toString() 方法,去除产生死循环的数据项
  • 为维护类的 对应属性添加 @JsonIgnore 注解(将属性忽略,spring mvc将对象转换为json格式字符串时忽略该属性,防止出现两个对象相互调用出现死循环)

问题得以解决:

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "mask_tab")
public class Mask implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "mask_id")
    private Integer id;
    @Column(name = "mask_name")
    private String name;

    //多对多关系映射(维护表)
    @JsonIgnore
    @ManyToMany(cascade=CascadeType.REFRESH,fetch = FetchType.EAGER)
    @JoinTable(name="mask_authority_tab", //中间表的名称
            //中间表 ma_mask_id 字段关联 mask_authority_tab 表的主键字段 mask_id
            joinColumns={@JoinColumn(name="ma_mask_id",referencedColumnName="mask_id")},
            //中间表 ma_mask_id 的字段关联 authority_tab 表的主键 authority_id
            inverseJoinColumns={@JoinColumn(name="ma_authority_id",referencedColumnName="authority_id")})
    private List<Authority> authorities = new LinkedList<>();
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "authority_tab")
public class Authority implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "authority_id")
    private Integer id;
    @Column(name = "authority_name")
    private String name;

    //多对多关系映射(被维护表)
    @ManyToMany(cascade=CascadeType.REFRESH,mappedBy="authorities")
    private List<Mask> masks = new LinkedList<>();
	
	//重写toString() 方法
    @Override
    public String toString() {
        return "Authority{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值