Zerobase/북 스터디

스프링 부트 핵심 가이드(장정우 지음) ch.9

LeeSHyun 2023. 7. 23. 22:43

9장: 연관관계 매핑

 

9-1 연관관계 매핑 종류와 방향

  • One To One: 일대일(1:1)
  • One To Many: 일대다(1:N)
  • Many To Many: 다대다(N:M)

연관관계는 어떤 엔티티를 중심으로 보느냐에 따라 상태가 달라진다.

데이터베이스에서는 두 테이블의 연관관계를 설정하면 외래키를 통해 서로 조인해서 참조하는 구조로 생성되지만 JPA를 사용하는 객체지향 모델링에서는 엔티티 간 참조 방향을 설정할 수 있다. 데이터베이스와 관계를 일치시키기 위해 양뱡향으로 설정해도 무관하지만 비즈니스 로직의 관점에서 봤을 때는 단방향 관계만 설정해도 해결되는 경우가 많다.

단방향과 양방향 관계 정리

  • 단방향: 두 엔티티의 관계에서 한쪽의 엔티티만 참조하는 형식이다
  • 양방향: 두 엔티티의 관계에서 각엔티티가 서로의 엔티티를 참조하는 형식이다.

연관관계가 설정되면 한 테이블에서 다른 테이블의 기본값을 외래키로 갖게 된다. 이런 관계에서는 주인(Owner)이라는 개념이 사용된다. 일반적으로 외래키를 가진 테이블이 그 관계의 주인이 되며, 주인은 외래키를 사용할 수 있으나 상대 엔티티는 읽는 작업만 수행할 수 있다.

 

9-3 일대일 매핑

예를 들어, 하나의 상품에 하나의 상품정보만 매핑되는 구조가 일대일 관계이다.

 

9-3-1 일대일 단방향 매핑

엔티티에서 일대일 매핑할 칼럼을 @OneToOne 어노테이션을 사용해서 매핑한다. @OneToOne 어노테이션은 다른 엔티티 객 체를 필드로 정의했을 때 일대일 연관관계를 매핑하기 위해 사용된다. @JoinColumn 어노테이션을 사용해 매핑할 외래키를 설정한다. @JoinColumn 어노테이션은 기본값이 설정돼 있어 자동으로 이름을 매핑하지만 의도한 이름이 들어가지 않기 때문에 name 속성을 사용해 원하는 컬럼명을 지정하는 것이 좋다.

@JoinColumn 속성

  • name: 매핑할 외래키의 이름을 설정한다.
  • referencedColumnName: 외래키가 참조할 상대 테이블의 칼럼명을 지정한다.
  • foreignKey: 외래키를 생성하면서 지정할 제약조건을 설정한다.(unique, nullable, insertable, updatable 등)

 

9-3-2 일대일 양방향 매핑

객체에서의 양방향 개념은 양쪽에서 단방향으로 서로를 매핑하는 것을 의미한다.

JPA에서도 실제 데이터베이스의 연관관계를 반영해서 한쪽의 테이블에서만 외래키를 바꿀 수 있도록 정의하는 것이 좋다. 이 경우 엔티티는 양방향으로 매핑하되 한쪽에게만 외래키를 줘야 하는데, 이때 사용되는 속성이 mappedBy이다. mappedBy는 어떤 객체가 주인인지 표시하는 속성이다.

 

9-4 다대일, 일대다 매핑

예를들어, 상품 테이블과 공급업체의 관계는 다대일, 일대다 관계로 볼 수 있다.

 

9-4-1 다대일 단방향 매핑

@ManyToOne 어노테이션을 이용해 외래키를 설정한다.

 

9-4-2 다대일 양방향 매핑

마찬가지로 양쪽에서 단방향으로 매핑하는 것이 양방향 매핑 방식이다. @OneToMany 어노테이션을 추가한다.

 

tip 지연로딩과 즉시로딩

JPA에서 지연로딩(lazy loading)과 즉시로딩(eager loading)은 중요한 개념이다. 엔티티라는 객체의 개념으로 데이터베이스를 구현했기 때문에 연관관계를 가진 각 엔티틴 클래스에는 연관관계가 있는 필드에 존재하게 된다. 연관관계와 상관없이 즉각 해당 엔티티의 값만 조회하고 싶거나 연관관계를 가진 테이블의 값도 조회하고 싶은 경우 등 여러 조건들을 만족하기 위해 등장한 개념이 지연로딩과 즉시로딩이다.

 

9-4-3 일대다 단방향 매핑

@OneToMany를 설정한다.

일대다 양방향 매핑은 @OneToMany를 사용하는 입장에서 어느 엔티티 클래스도 연관관계의 주인이 될 수 없기 때문에 사용하지 않는다.

 

9-5 다대다 매핑

다대다(M:N) 연관관계는 실무에서 거의사용되지 않는 구성이다. 굳이 예를 들면, 상품과 생산업체의 예로 한 종류의 상품이 여러 생산업체를 통해 생산될 수 있고, 생산업체 한 곳이 여러 상품을 생산할 수도 있다.

교차 엔티티라고 부르는 중간 테이블을 생성해서 다대다 관계를 일대다 또는 다대일 관계로 해소한다.

 

9-5-1 다대다 단방향 매핑

@ManyToMany 어노테이션을 설정한다. 

 

9-5-2 다대다 양방향 매핑

두 칼럼에 @ManyToMany를 설정한다.

다대다 연관관계를 설정하면 중간 테이블을 통해 연관된 엔티티의 값을 가져올 수 있다. 다만 다대다 연관관계에서는 중간 테이블이 생성되기 때문에 예기치 못한 쿼리가 생길 수 있다. 즉, 관리하기 힘든 포인트가 발생한다는 문제가 있다. 그렇기 때문에 이러한 다대다 연관관계의 한계를 극복하기 위해서는 중간 테이블을 생성하는 대신 일대다 다대일로 연관관계를 맺을 수 있는 중간 엔티티로 승격시켜 JPA에서 관리할 수 있게 생성하는 것이 좋다.

 

9-6 영속성 전이

영속성 전이(cascade)란 특정 엔티티의 영속성 상태를 변경할 때 그 엔티티와 연관된 엔티티의 영속성에도 영향을 미쳐 영속성 상태를 변경하는 것을 의미한다.

영속성 전이 타입

종류 설명
ALL 모든 영속 상태 변경에 대해 영속성 전이를 적용
PERSIST 엔티티가 영속화할 때 연관된 엔티티도 함께 영속화
MERGE 엔티티를 영속성 컨텍스트에 병합할 때 연관된 엔티티도 병합
REMOVE 엔티티를 제거할 때 연관된 엔티티도 제거
REFRESH 엔티티를 새로고침할 때 연관된 엔티티도 새로고침
DETACH 엔티티를 영속성 컨텍스트에서 제외하면 연관된 엔티티도 제외

영속성 전이에 사용되는 타입은 엔티티의 생명주기와 연관이 있다.

 

9-6-1 영속성 전이 적용

영속성 전이 타입을 설정하면 영속 상태의 변화에 따라 연관된 엔티티들의 동작도 함께 수행할 수 있어 개발의 생산성이 높아진다. 다만 자동 설정으로 동작하는 코드들이 정확히 어떤 영향을 미치는지 파악할 필요가 있다. 예를 들어, REMOVE와 REMOVE를 포함하는 ALL 같은 타입을 무분별하게 사용하면 연관된 엔티티가 의도치 않게 모두 삭제될 수 있기 때문에 다른 타입보다 더욱 사이드 이펙트(side effect)를 고려해서 사용해야 한다.

 

9-6-2 고아 객체

JPA에서 고아(orphan)란 부모 엔티티와 연관관계가 끊어진 엔티티를 의미한다. JPA에는 이러한 고아 객체를 자동으로 제거하는 기능이 있다. 물론 자식 엔티티가 다른 엔티티와 연관관계를 가지고 있다면 이 기능은 사용하지 않는 것이 좋다.

'orhpanRemoval = true' 속성은 고아 객체를 제거하는 기능이다.