민팽로그

[jpa 연관관계] 다대일 관계: 양방향 매핑 무한루프 본문

jpa

[jpa 연관관계] 다대일 관계: 양방향 매핑 무한루프

민팽 2021. 8. 26. 19:01

유저에 따른 오답노트 api를 만들면서 오답노트 테이블이에 외래키를 두어 유저 테이블을 참조하도록 하였고, jpa 양방향 매핑을 이용하여 유저 테이블에서 오답노트를 참조할 수 있도록 하였다. 사실 오답노트쪽에서 유저 테이블을 참조하는 기능은 필요가 없지만, 다대일 관계에서 일 쪽에서 다 쪽으로 단방향 매핑을 하는것보다는 양방향 매핑이 좋다고 하여 이유는 잘 모르지만 양방향으로 구현하였다.

 

양방향 매핑을 하려면  @OneToMany(일), @ManyToOne(다) 어노테이션을 각각 붙여준다.

단반향은 @ManyToOne이나 @OneToMany만 필요한 쪽에 사용하면 되고 @OneToMany단방향 매핑은 사용하지 않는게 좋다고 함(왜..?)

 

User 클래스

@Getter
@NoArgsConstructor
@Entity
public class User extends Timestamped {
    @Id
    private String email;

    @Column
    private String nickname;

    @OneToMany(mappedBy = "email") //WrongQuiz 엔티티의 email로 매핑
    List<WrongQuiz> wrongQuizs;

    @Builder
    public User(String email, String nickname) {
        this.email = email;
        this.nickname = nickname;
    }

    public String update(String nickname) {
        this.nickname = nickname;

        return this.nickname;
    }
}

 

WrongQuiz 클래스

@Getter
@Entity
@Table(name = "WRONGQUIZ")
@NoArgsConstructor
public class WrongQuiz {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long serialId;

    @ManyToOne //User 엔티티의 email 참조
    @JoinColumn(name = "email", nullable = false)
    private User email;

    @ManyToOne
    @JoinColumns({
            @JoinColumn(name = "stage_num", referencedColumnName = "stage_num", nullable = false),
            @JoinColumn(name = "quiz_num", referencedColumnName = "quiz_num", nullable = false)
    })
    private GameOXQuiz gameOXQuiz;
}

 

무한루프 문제 발생

이 경우 컨트롤러에서 엔티티를 참조하여 JSON으로 변환하는 과정에서 양방향 매핑이 되어있는 두 엔티티 사이의 끊임없는 순환참조로 인해 무한루프에 빠지기 쉽다. 처음 오류를 마주했을 때 순환참조 문제일 것 같다는 느낌이 들긴 했는데 아무튼 생각한 결과가 아니라 당황스러웠다..

 

해결

부모 클래스 쪽에는 @JsonManagedReference 어노테이션을, 자식 클래스 쪽에는 @JsonBackReference 어노테이션을 붙여주면 해결할 수 있다.

 

User 클래스

@Getter
@NoArgsConstructor
@Entity
public class User extends Timestamped {
    @Id
    private String email;

    @Column
    private String nickname;
    
    @JsonManagedReference //추가한 어노테이션
    @OneToMany(mappedBy = "email") //WrongQuiz 엔티티의 email로 매핑
    List<WrongQuiz> wrongQuizs;

    @Builder
    public User(String email, String nickname) {
        this.email = email;
        this.nickname = nickname;
    }

    public String update(String nickname) {
        this.nickname = nickname;

        return this.nickname;
    }
}

 

WrongQuiz 클래스

@Getter
@Entity
@Table(name = "WRONGQUIZ")
@NoArgsConstructor
public class WrongQuiz {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long serialId;
    
    @JsonBackReference //추가한 어노테이션
    @ManyToOne //User 엔티티의 email 참조
    @JoinColumn(name = "email", nullable = false)
    private User email;

    @ManyToOne
    @JoinColumns({
            @JoinColumn(name = "stage_num", referencedColumnName = "stage_num", nullable = false),
            @JoinColumn(name = "quiz_num", referencedColumnName = "quiz_num", nullable = false)
    })
    private GameOXQuiz gameOXQuiz;
}

 

 

 

 

 

참조

JPA에서 순환참조 무한루프를 해결하는 방법 - study blog (icoul.github.io)

 

JPA에서 순환참조 무한루프를 해결하는 방법

JPA에서의 순환참조 JPA는 ORM이기 때문에 RDB를 관리하는데 있어서 양방향 참조를 필요로 한다. 이러한 참조는 필수적인 것은 아니지만 Entity는 데이터의 구조를 보여주는 역할도 하기 때문에 명시

icoul.github.io

 

 

 

+ 또다른 원인이 있다는 말을 들었다. 좀 더 알아보면 좋을 것 같다. 엔티티를 반환하는 과정에서 생기는 JPA쪽의 문제와 DI 시 발생하는 문제 2가지를 의미했던게 맞는걸까? 더 공부하고 정리!

https://keichee.tistory.com/446

https://siyoon210.tistory.com/170

https://madplay.github.io/post/why-constructor-injection-is-better-than-field-injection

https://k3068.tistory.com/m/32?category=919284 

https://yaboong.github.io/spring/2019/08/29/why-field-injection-is-bad/

 

 

'jpa' 카테고리의 다른 글

DB 운영과 @Transactional  (0) 2021.09.14
[ORM] JPA와 연관관계  (0) 2021.09.14
Comments