JPA

다양한 연관관계 매핑 - 2

방구석 대학생 2020. 10. 4. 23:37

"인프런 - 자바 ORM 표준 JPA 프로그래밍 강의를 듣고 작성한 글 입니다."

www.inflearn.com/course/ORM-JPA-Basic#

 

자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런

JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다. 초급 웹 개발 프로그

www.inflearn.com

 

- 일대일(1 : 1) 연관관계 매핑

일대일 연관관계는 연관관계의 주인 클래스를 바꿔도 똑같이 일대일 연관관계를 적용할 수 있다.

즉, 주 테이블 이나 대상 테이블 중에 아무곳이나 외래 키 선택이 가능하다.

일대일 연관관계 매핑을 활용 하려면 외래 키에 데이터베이스 유니크 제약 조건이 추가되어야 한다.

(안해도 되긴 하는데, 그러려면 애플리케이션 에서 관리를 엄청 잘해야 한다고 한다.)

 

- 예시 Member 클래스, Locker 클래스간 일대일 연관관계 에서, 주 클래스인 Member 클래스의 테이블에 외래 키를 지정하여 단방향으로 연관관계를 매핑한 경우

 

Locker 클래스를 생성 한 후 Id 어노테이션을 통해 기본 키를 생성한 다음,

Member 클래스에서 @OneToOne 어노테이션을 활용하여 객체 참조를 함으로서 일대일 단방향 연관관계를 매핑할 수 있다.

 

- Member.java

@OneToOne
@JoinColumn(name = "LOCKER_ID")
private Locker locker;

- Locker.java

@Id @GeneratedValue
private Long id;

private String name;

 

위와 같이 참조를 작성한 후 실행하면 다음과 같은 hibernate SQL 을 얻을 수 있다.

Hibernate: 
    
    create table Locker (
       id bigint not null,
        name varchar(255),
        primary key (id)
    )
Hibernate: 
    
    create table Member (
       MEMBER_ID bigint not null,
        USERNAME varchar(255),
        LOCKER_ID bigint, // Locker 테이블의 기본 키를 외래 키로 가져왔다.
        TEAM_ID bigint,
        primary key (MEMBER_ID)
    )

 

- 일대일 연관관계 에서 양방향 매핑

일대일 연관관계에서 양방향 매핑을 원할 경우 다대일 연관관계 에서 했던 바와 같이 @OneToOne 어노테이션 에서 mappedBy 속성을 활용해준다.

 

 

- Locker.java

@OneToOne(mappedBy = "locker")
private Member member;

 

일대일 연관관계 에서는 다대일 연관관계와 같이 외래 키가 있는 테이블이 연관관계의 주인이다.

그런데, 객체에서의 참조와는 달리 다른 테이블에 외래 키가 들어있으면 어떻게 될까?(교차 매핑의 경우)

정답은? 불가능하다.(JPA 에서 아예 지원을 하지 않는다.)

 

그런데 대상 테이블에 외래 키가 있는 단방향 연관관계(교차 매핑)는 JPA 가 지원을 하지 않으나, 양방향 연관관계는 지원 해준다.

어차피 양방향 관계라면, 연관관계의 주인이 아닌 대상 도메인 클래스에 선언해놓은 주인 클래스의 객체 참조를 통해 대상 테이블에 연관관계 매핑을 해 줄 수 있기 때문이다.

(일대일 연관관계 에서 외래 키는 어떤 테이블에 있어도 상관없다, 즉 대상 테이블을 연관관계의 주인으로 만들고 본래 연관관계의 주인이였을 도메인 클래스를 읽기만 가능한 대상 클래스로 바꿔주면 된다는 뜻이다. - 연관관계의 주인 자체가 바뀌게 된다.)

 

 

* 일대일 연관관계 정리

위와 같이 일대일 양방향 연관관계 에서는 어느쪽이 연관관계의 주인이 되든 상관없으나, 만약 시간이 지나서 해당 연관관계가 N : 1 로 바뀔 경우 까지 생각해야 한다면 어느쪽을 연관관계의 주인으로 지정해주어야 할 까?

여기서 연관관계의 주인을 정하는대 있어, 주 테이블에 외래 키를 주는 경우와 대상 테이블에 외래 키를 주는 경우로 갈리게 된다.

 

- 주 테이블에 외래 키를 주는 경우

: 주 객체가 대상 객체의 참조를 가지는 것 처럼, 주 테이블에 외래 키를 두고 대상 테이블을 찾는다.

주로 객체지향 개발자가 선호하는 방식이며 JPA 매핑이 편리하다.

장점 : 주 테이블만 조회해도 대상 테이블에 데이터가 있는지 확인 가능하다.

단점 : 값이 없으면 외래 키에 null 값을 허용하개 된다.

 

- 대상 테이블에 외래 키를 주는 경우

: 주로 전통적인 데이터베이스 개발자가 선호한다.

장점 : 주 테이블과 대상 테이블의 구조를 유지하면서 일대일 에서 일대다 연관관계로 변경할 수 있다.

단점(치명적임) : 프록시 기능의 한계로 인해 지연 로딩으로 설정해도 항상 즉시 로딩된다.

-> 프록시 객체를 만들려면 주 테이블 도메인 클래스에 값이 있는지 없는지 알아야 한다.(주 테이블에 외래 키가 있다면 JPA 가 주 테이블에만 select 쿼리를 전달하면 된다.)

그런데 만약 외래 키가 주 테이블이 아닌 대상 테이블에 존재한다면 어떻게 될까? -> 이렇게 되면 값이 있는지 없는지 알아야 할 때 주 테이블만 조회해서 될 게 아니라 대상 테이블까지 같이 조회해야 한다.

 

어차피 쿼리가 나가는거 주 테이블의 도메인 클래스를 프록시 객체로 만들 필요가 없어지는 것이다.

때문에 지연 로딩으로 설정해도 대상 테이블에 외래 키가 있다면 무조건 즉시 로딩이 실행된다.

왜? 어차피 대상 테이블에도 쿼리를 전달해야 하기 때문이다.

그러므로 주 테이블에 외래 키가 있는 방식을 선호하게 되나, 그러려면 DBA 분과 충분한 상의가 이루어져야 한다.

 

 

프록시에 대해서는 뒤에 있을 강의에서 자세히 설명된다.