Java Spring Boot - JPA : StackOverflowError with a @ManyToMany relation

标签 java spring jpa stack-overflow

我目前正在使用 JavaSpringBoot 中的 API 开发应用程序,我需要添加用户( friend )之间的关系。为此,我创建了一个包含两个字段的多对多关系:

CREATE TABLE friend_relation
(
    fk_id_friend   integer REFERENCES users (id) NOT NULL,
    fk_id_user     integer REFERENCES users (id) NOT NULL,
    PRIMARY KEY (fk_id_friend, fk_id_user)
);
当我与用户连接并添加关系时:一切都很好,但是如果我连接到另一个用户添加为 friend 的帐户之一,则会出现 StackOverflowError。
我知道这是因为数据库中的条目几乎相同,但我不知道如何让我的实体正确。
目前每个用户必须单独添加另一个,我想我必须创建一个好友请求系统,但我再次被阻止。
我是否必须在我的friend_relation 表中创建一个“有效”字段。如果是这样,我该如何使用它?我应该为这个表创建一个特定的实体还是将它留在用户实体中?
目前,这就是我的用户实体的样子:
@Entity
@Table(name = "users")
@Data
@Accessors(chain = true)
public class UserEntity {

    @Id
    @SequenceGenerator(name = "users_generator", sequenceName = "users_sequence", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "users_generator")
    @Column(name = "id")
    private Integer id;

    [...]

    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(
            name = "friend_relation",
            joinColumns = @JoinColumn(name = "fk_id_user", referencedColumnName = "id", nullable = false),
            inverseJoinColumns = @JoinColumn(name = "fk_id_friend", referencedColumnName = "id", nullable = false)
    )
    private List<UserEntity> friends = new ArrayList<>();

}
尝试修改我的实体以避免错误时:
    @ManyToMany
    @JoinTable(name="friend_relation",
            joinColumns=@JoinColumn(name="fk_id_user"),
            inverseJoinColumns=@JoinColumn(name="fk_id_friend")
    )
    private List<UserEntity> friends;

    @ManyToMany
    @JoinTable(name="friend_relation",
            joinColumns=@JoinColumn(name="fk_id_friend"),
            inverseJoinColumns=@JoinColumn(name="fk_id_user")
    )
    private List<UserEntity> friendOf;
我在互联网上寻找资源但没有找到,可能是我搜索得不好,如果已经给出答案,我提前道歉。
如果您能帮助我,我将非常高兴,在此先感谢您!
(对于谷歌翻译我很抱歉,我宁愿不使用我粗糙的英语)✌

好的抱歉更新,我不发布股权跟踪:https://pastebin.com/Ls2qRpU4
当我让我的用户站在前面时会发生这种情况。我正在尝试连接,但我无法连接,因为发生此错误。

最佳答案

首先,我注意到一个 @Data在你的实体上,我想它来自 Lombok 项目?请注意,Lombok 生成的方法可能会触发延迟加载,并且自动生成的 ID 的 equals/hashCode 存在问题。 (见 herehere)
现在你的问题:
这确实是一个 JSON 序列化问题。你有循环引用, jackson 在公元前循环运行。它不知道该停在哪里。
您可以使用 DTO 投影来自己解决这个圆,例如:

public class UserDto {
    public Integer id;
    public List<Integer> friends; // List of IDs
}
您也可以使用 Jackson 注释来实现几乎相同的功能,例如 @JsonIdentityInfo . Here's an article about it.
@JsonIdentityInfo(
    generator = ObjectIdGenerators.PropertyGenerator.class, 
    property = "id")
@Entity
@Table(name = "users")
@Data
@Accessors(chain = true)
public class UserEntity {

    @Id
    @SequenceGenerator(name = "users_generator", sequenceName = "users_sequence", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "users_generator")
    @Column(name = "id")
    private Integer id;

    [...]

    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(
            name = "friend_relation",
            joinColumns = @JoinColumn(name = "fk_id_user", referencedColumnName = "id", nullable = false),
            inverseJoinColumns = @JoinColumn(name = "fk_id_friend", referencedColumnName = "id", nullable = false)
    )
    private List<UserEntity> friends = new ArrayList<>();

}
当您拥有具有循环引用或非常大的对象树的复杂实体时,您通常必须认真考虑如何序列化它们 - 特别是在考虑 LazyLoading 时。我花了拍品 在复杂的专业项目中花费时间。简单的自动生成的 DTO 和序列化有时不会削减它。

关于Java Spring Boot - JPA : StackOverflowError with a @ManyToMany relation,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62585553/

相关文章:

java - Spring在条件类的子类中注入(inject)bean

java - 实体无法保存外键实体

java - 获取 Android 上的 cpu、ram 和网络使用统计信息

java - ARToolKit - 无法添加 NFT 标记,标记类型未知

java - 从父类对象设置所有子类变量

java - 我有一个 mysql 数据库和一个表,我将它编码为 json,当我在浏览器中运行 php 文件时,当我从 android 获取它时,它会有所不同

java - LazyList.decorate - 实例化工厂 : The constructor must exist and be public exception

spring - 如何注入(inject)@products方法

java - @JsonApiRelationId 和 @JsonApiRelation 有什么区别?

postgresql - JPA 3 Hibernate + PostgreSQL 9.6.3 查询中出现限制错误