JPA 양방향 연관관계 세팅 및 주의사항

Spring Data JPA와 JPA 양방향 연관관계를 세팅하고 사용 시 주의할 점에 대해서 정리하였다. 밑은 간단한 예제 코드를 준비하였다.

User는 다양한 Knowledge을 등록할 수 있다. 정리하면 User는 N개의 Knowledge를 등록할 수 있다고 가정한다. 두 엔티티 간의 관계는 1:N이다.

소스 코드

User.java

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class User {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "user_id")
    private Long id;

    @Column(length = 60)
    private String email;

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

Knowledge.java

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class Knowledge {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "knowledge_id")
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id", nullable = false)
    private User user;

    @Column(length = 20)
    private String title;

    @Column(columnDefinition = "TEXT")
    private String content;

    @Builder
    public Knowledge(User user, String title, String content) {
        this.user = user;
        this.title = title;
        this.content = content;
    }
}

현재 @ManyToOne을 활용하여 단방향 연관관계를 세팅해주었다.

양방향 연관관계 세팅하기

연관관계의 주인은 외래키가 있는 곳이다. User와 Knowledge 중 user_id를 외래키로 가지고 있는 곧은 N 쪽의 Knowledge가 된다. 그렇기 때문에 외래키는 Knowledge 테이블에 세팅되어 있다.

이제 User 쪽에서 자신이 등록한 knowledge 목록에 접근할 수 있도록 추가적인 연관관계를 세팅해준다.

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class User {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "user_id")
    private Long id;

    @Column(length = 60)
    private String email;

    @OneToMany(mappedBy = "user")
    private List<Knowledge> knowledges = new ArrayList<>();

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

MappedBy는 주인이 아님을 설정한다. 속성의 값은 연관관계의 주인이 Knowledge.user 라는 것을 암시한다.

User.Knowledges와 Knowledge.User 중 연관관계의 주인은 Knowledge.user이 된다.

연관관계의 주인?

연관관계의 주인이라는 의미는 두 엔티티 관계에서 주인으로서 역할은 하는 것이 아니다. 단순히 데이터베이스에서 외래키를 가지고 있기 때문에 외래키를 관리하는 주인이 된다. 그렇기 때문에 주인이 아닌 User.knowledges를 통해서는 단순히 데이터베이스의 값을 읽기만 가능하다.

양방향 연관관계 사용 시 주의할 점

연관관계의 주인이 아닌 곳에 데이터 삽입

가장 치명적인 실수는 연관관계의 주인이 아닌 곳에서 데이터를 삽입하는 것이다. 오직 연관관계의 주인 만이 외래키의 값을 변경할 수 있다.