본문 바로가기

Tech/JPA

[JPA] 상속관계 매핑

반응형

상속관계 매핑

객체는 부모 클래스와 자식 클래스의 상속관계가 있지만, 관계형 데이터베이스는 상속관계가 존재하지 않는다. 대신 데이터베이스에는 슈퍼타입, 서브타입 관계라는 모델링 기법이 있는데, 이 기법이 객체의 상속과 유사한다. 이 방법을 객체의 상속과 매핑하여 상속관계를 구현한다.

 

※ 슈퍼타입 - 서브타입 모델링

공통 속성을 가진 여러개의 데이터들이 존재할 때, 이들을 어떻게 관리할 것인지에 대한 방법이다.
슈퍼타입 모델링은 전체 데이터를 하나의 슈퍼 테이블로 관리하는 방식이다. 이 방식으로 관리하는 경우, 전체 검색에 유리하지만 공통 속성을 제외한 나머지 속성에 대해서 NULL 값이 저장되는 단점이 있다.
서브타입 모델링은 각 데이터들을 공통 속성 + 서브 속성으로 각각의 서브타입별로 데이터를 저장하는 테이블을 설계하는 방식이다. NULL 값은 줄어들지만, 테이블이 많아지고, 전체 조회시에 UNION 을 사용해야해서 이를 유의해야한다.

 

상속관계 매핑을 구현할 때 객체 쪽은 상속관계를 가지기 때문에 구현에 변경은 없다. 다만 데이터베이스의 설계를 어떤 구조로 상속관계와 매핑할 것인지 설계해야한다.

상속관계 매핑 전략

@Inheritance 어노테이션을 엔티티 클래스에 선언하여 상속관계 매핑 전략을 지정할 수 있다.

상속관계 매핑 전략으로는 조인 전략 (JOINED), 단일 테이블 전략 (SINGLE_TABLE), 개별 구현 클래스별 테이블 전략 (TABLE_PER_CLASS) 등이 있다.

1) 조인 전략

부모 엔티티의 ID 를 자식 엔티티의 외래키로 주어 데이터베이스의 조인으로 연관관계를 맺도록 하는 전략이다. 부모 엔티티 선언시에 @Inheritance(strategy = Inheritance.JOINED) 로 선언하면 된다.

 

@DIscriminatorColumn 을 엔티티에 선언하여 단일 테이블의 DTYPE 컬럼을 조인 전략에도 추가해줄 수 있다. DTYPE 컬럼은 해당 데이터가 어떤 자식 엔티티인지를 표현하는 컬럼이다. 상속관계에서는 DTYPE 을 가지는 것이 권장사항이다.

 

이 전략을 사용하면 테이블 정규화, 외래키 참조 무결성 제약 조건 등의 활용이 가능하다. 그리고 저장공간을 효율화할 수 있다. 하지만 조회시 조인을 많이 사용하고, 데이터 저장시에 부모 테이블과 자식 테이블 각각에 데이터를 저장하기 위해 INSERT 가 2번 호출된다. 또한 단일 테이블과 비교하여 테이블이 많고 조인이 많아서 쿼리가 복잡해진다.

2) 단일 테이블 전략

슈퍼타입 모델링을 적용한 전략으로 모든 자식 타입의 컬럼들을 부모 타입이 포함하여 테이블이 생성된다. 이렇게 생성된 테이블에 타입을 의미하는 컬럼, DTYPE 을 생성하여 어떤 타입인지 구분할 수 있도록 한다.

 

부모 엔티티를 @Inheritance(strategy = Inheritance.SINGLE_TABLE) 로 선언하여 구현한다. 이때 @DIscriminatorColumn 없이도 DTYPE 이 자동 생성된다.

 

이 전략은 부모 테이블에서 바로 데이터를 조회할 수 있어서 조인문이 필요없고 속도가 빠르다. 하지만 자식 엔티티와 매핑한 컬럼들은 모두 null 을 허용해야한다. 그리고 부모 테이블에 모든 데이터를 저장하기 때문에 적정량을 넘어가는 경우 오히려 조회 속도가 느려질 수 있다.

3) 구현 클래스 개별 테이블 전략

부모 테이블을 따로 만들지 않고 각각의 테이블이 부모 테이블의 컬럼을 모두 가지고 있도록 설계하는 방식이다. 부모 엔티티를 @Inheritance(strategy = Inheritance.TABLE_PER_CLASS) 로 선언하면 된다.

 

이 방식으로 구현하는 경우 부모 테이블의 객체는 생성되지 않는다. 부모 클래스 타입으로 자식 객체의 타입을 조회할 때 모든 자식 테이블을 조회해야하는 성능상의 문제가 있다.

 

서브 타입을 명확하게 구분하고, not null 조건을 사용할 수 있는 장점이 있다. 하지만 여러 테이블을 함께 조회할 때 UNION 을 사용해야 하기 때문에 속도가 느리다. 또한 시스템 유지보수 관점에서 변경이 일어나면 모든 엔티티를 변경해야해서 실무에서는 사용하지 않는 것이 좋다.

@MappedSuperclass

상속관계와 직접적으로 관련있는 어노테이션은 아니다. 여러 엔티티에서 공통 매핑 정보가 필요한 경우에 사용하는 어노테이션이다. 상속관계 매핑과는 다르며, 엔티티가 아니기 때문에 테이블과 매핑되지 않는다.

다만 해당 어노테이션이 붙어있는 클래스를 상속받은 자식 클래스에 매핑 정보만 제공해준다.

 

엔티티가 아니기 때문에 JPA 에서 해당 클래스 타입으로 조회는 불가하다.

실제 해당 클래스를 사용할 일은 없기 떄문에 추상클래스로 구현하는 것을 권장한다.

 

해당 어노테이션으로 선언된 클래스를 상속받은 자식 클래스는 부모 클래스에 있는 멤버를 상속받아서 테이블과 매핑에 사용한다. 주로 등록일, 수정일과 같이 여러 클래스에 공통적으로 들어가는 값들을 포함한다.

반응형