티스토리 뷰

반응형

1. Entitiy간의 연관관계(방향)이란?

데이터베이스상에서는 관계를 맺어주기만 하면 자동으로 서로간의 양방향 참조가 가능합니다. 하지만 객체지향의 (Entity) 클래스간에는 '참조 방향'을 지정해주어야 하는데, 어떤 '방향성'을 고려해야하는지는 굉장히 중요합니다. (처음에는 Entity간의 양방향성을 남발했지만, 공부를 지속하면서 양방향성의 위험성을 알게 되었습니다.) 


2. 단뱡향vs양방향

방향을 가져야 하는 경우는 어떤 경우인지 부터 보겠습니다. 먼저 객체지향적인 관점에서 생각해보면 A클래스와 B클래스가 연관관계일때, A클래스는 B클래스를 사용하게 되고 이런 경우에 방향성을 갖습니다. 반대로 B클래스가 A클래스를 사용하게 되면 역시 방향성을 갖습니다. 그러나 방향성을 남발하게 되면 성능상의 큰 문제가 발생 할 수있습니다. 예를들어 게시판을 구현한다고 할때, 한명의 이용자가 수많은 게시판의 글을 작성했고 회원클래스가 게시물클래스의 방향을 갖는 경우, 해당 회원의 게시물을 불러오는 순간(getArticles) DB상에 큰 부담이 생길 수 있습니다. 그래서 방향성을 갖게되어서 성능상 문제가 생기는 경우를 생각해보고, 부담이 생기는 방향성은 배제하도록 신중하게 설계해아합니다. (만약 회원이 작성한 글에 대해서 조회를 하고 싶다면, Repository를 구현하고 페이징 기능을 사용해서 조회합니다.)


참고로, 데이터베이스간의 관계와 Entity의 방향성은 별개로 염두해야합니다. 앞서서도 언급했지만, 데이터베이스상에서는 이미 양방향 참조가 가능한 상태고, Entity의 방향성은 객체간의 참조 방향을 말하는 것입니다.


가능한 단방향만으로 구현을 해보고 양방향이 필요한 경우에 성능과 편의성을 고려하여서 양방향을 추가하는 방식이 좋습니다.


3. 양방향 연관관계의 주인

두 개의 Entity 클래스가 양방향으로 서로 참조를 하고 있으면, '연관관계의 주인'을 지정해줘야 합니다. 양방향간의 참조가 되어있을 때 양쪽에서 모두 값을 갱신하게 된다면 데이터간의 충돌이 일어 날 수 있습니다. 그러므로 연관관계의 주인만이 외래키를 관리하여 갱신(등록, 수정, 삭제)를 할 수 있고, 반대편은 읽기만 가능하도록 만들기 위함입니다. 연관관계의 주인은 FK(외래키)가 명시된 Entity클래스로 설정합니다. (쉽게말해 mappedBy라는 옵션을 사용하는 쪽은 주인이 아닙니다). 


개발과정에서 주인이 아닌쪽에서 갱신을 시도해봤자. DB상에서는 반영이 되지 않습니다. 이런경우 연관관계 주인 설정을 어떤식으로 진행했는지 확인해보기 바랍니다.


(+ 데이터베이스상에서 컬럼값으로 연관된 FK를 가지는 쪽을 주인으로 두는 것이 좋습니다.)


4. 연관관계(방향) 설정하기

예제에 사용될 클래스명은 'A'클래스와 'B'클래스로 하겠습니다. 아래 표를 보시면 단방향과 양방향시에 설정방법을 간단하게 기입했습니다. 단방향시에 방향성은 A클래스에서 B클래스 입니다. (A → B)

4.1 ManyToOne(N:1) 설정

다대일 설정시의 FK(외래키)는 N(Many)쪽에 둡니다.

N (Many)

1 (One)

단방향

@Entity
public class A {
    . . .
 @ManyToOne
 @JoinColumn(name = "b_id")
 private B b;
}
@Entity
public class B {

    . . .

 //필드값 없음(방향성 없음)
}

양방향

@Entity
public class A {
    . . .
 @ManyToOne
 @JoinColumn(name = "b_id")
 private B b;
}

@Entity
public class B {
    . . .
 //연관관계의 주인은 A클래스
 @OneToMany(mappedBy = "b")
 private Set<A> a;
}


4.2 OneToMany(1:N) 설정

다대일 설정시의 FK(외래키)는 N(Many)쪽에 둡니다. 하지만 N(Many)쪽에서 단방향 참조를 하고 있지 않으면 FK(외래키)설정할 필드값이 존재하지 않습니다. 그러므로 FK(외래키) 설정은 1(One)쪽에서 설정합니다. 양방향 설정을 하기 위해서는 ManyToOne의 양방향 구현방식을 사용합니다.

1 (One)

N (Many)

단방향

@Entity
public class A {
    . . .
 @OneToMany
 @JoinColumn(name = "a_id")
 private Set<B> b;
}
@Entity
public class B {

    . . .

 //필드값 없음(방향성 없음)
}

양방향

-

-


4.3 OneToOne(1:1) 설정

일대일 관계에서는 '주(主)테이블'을 정해야 합니다. 주테이블이라는 것은 단독적으로도 사용가능한 테이블을 말합니다. (혹은 기획상의 확장성을 고려해서 주테이블을 결정하기도 합니다.) 아래표에서는 왼쪽열이 주테이블, 오른쪽열이 대상테이블 입니다. 참고로 대상테이블에 외래키가 있는 단방향은 구현할 수 없습니다.

1 (One) - 주테이블

1 (One) - 대상테이블

단방향

@Entity
public class A {
    . . .
 @OneToOne
 @JoinColumn(name = "b_id")
 private B b;
}
@Entity
public class B {

    . . .

 //필드값 없음(방향성 없음)
}

양방향

@Entity
public class A {
    . . .
 @OneToOne
 @JoinColumn(name = "b_id")
 private B b;
}

@Entity
public class B {
    . . .
 //연관관계의 주인은 A클래스
 @OneToOne(mappedBy = "b")
 private A a;
}


4.4 ManyToMany(M:N) 설정

다대다 관계를 구현시에 매핑테이블이 양쪽 테이블의 FK만을 갖는다면, 굳이 엔티티를 만들필요가 없습니다. (반대로 얘기하면, FK이외에 필드값을 가져야 하는 경우는 Entity클래스로 만들어야 합니다.) ManyToMany는 Entity클래스로 만들필요가 없는 매핑테이블일 경우에 사용합니다.

M (Many)

N (Many)

단방향

@Entity
public class A {
    . . .
@ManyToMany
@JoinTable(name = "a_b", //매핑(연결) 테이블의 이름
  joinColumns = @JoinColumn(name = "a_id"),
  inverseJoinColumns = @JoinColumn(name = "b_id")
private Set<B> b;
}
@Entity
public class B {


    . . .


 //필드값 없음(방향성 없음)
}

양방향

@Entity
public class A {
    . . .
@ManyToMany
@JoinTable(name = "a_b", //매핑(연결) 테이블의 이름
  joinColumns = @JoinColumn(name = "a_id"),
  inverseJoinColumns = @JoinColumn(name = "b_id")
private Set<B> b;
}

@Entity
public class B {

    . . .

 //연관관계의 주인은 A클래스
 @ManyToMany(mappedBy = "b")
 private Set<A> A;
}

mappedBy 설정이 없는 곳이 연관관계 주인입니다.



참고

T아카데미 - JPA 프로그래밍 기초 (김영한님)

반응형
댓글