JPA

[JPA] 상속관계 매핑

행복하개! 2020. 10. 20. 16:11

 

 

 

먼저 객체지향에는 상속이라는 것이 있다. 하지만 관계형 데이터베이스에는 상속이라는 관계가 주어지지 않는다. 하지만 조금 비슷한 것을 보자면, 슈퍼타입과 서브타입이라는 것이 존재한다. 만약 Item이라는 테이블이 존재할때, 키나 DTYPE을 통해서 Album인지 Movie인지 Book인지 등등 어떤 종류인지 구분해내는 것이다.

 

 

 

 

이런 구현 전략을 위해서 JPA는 3가지의 어노테이션을 제공한다. 

1. @Inheritance(strategy = InheritanceType.JOINED)
2. @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
3. @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)

 

 

 

1. 조인 전략

 

먼저 JOINED전략은 테이블을 상속관계에 맞게 나눠서 생성하는 방법이다. 따라서 조회시에 테이블을 JOIN하고 쿼리가 날라간다.

이 조인 전략의 장점은 테이블을 데이터베이스 정규화에 맞기 조인을 할 수 있다는 점이고, 외래 키 참조 무결성 제약조건을 활용가능하다는 장점이 있다. 또한 테이블을 나눠서 필요한 값만 저장하기 때문에 저장공간이 낭비되지 않는다. 

 

다만 단점은 조회시에 반드시 조인을 해야하기 때문에 성능이 떨어질 수 있다. 또한 조회 쿼리가 복잡해질 수 있고, 데이터를 저장할때 테이블이 나누어져있기 때문에 삽입 쿼리를 두번 날려야한다.

 

추가적인 어노테이션으로 @DiscriminatorColumn 가 존재하는데 이는 ITEM에 DTYPE을 넣어주는 것이다. DTYPE이 존재해야 운영상에 어느 테이블이 추가되면서 이 ITEM 테이블이 추가되었는지 알 수 있기 때문이다. name을 바꿔서 넣을 수 있지만 데이터베이스 설계상 약어는 남용하지 말자. 만약 Album Movie등 자식의 DTYPE을 직접 설정해야 한다면@DiscriminatorValue를 이용하면 된다.

 

 

 

2. 단일 테이블 전략

 

말 그대로 슈퍼 서브를 나누지 않고 하나의 테이블에 때려박는(?) 전략이다.

이 전략은 먼저 DTYPE이 기본으로 들어간다. 하나의 테이블에 때려박기 때문에 이게 어떤 thing인지 구분할 필요가 있다. 이를 위해 DTYPE은 default로 들어간다.

 

이 전략에도 당연히 장단점이 존재한다. 장점은 하나의 테이블에서 관리하기 때문에 조인이 필요가 없고 그렇기 때문에 조회 성능이 빠르다. 그렇기에 조회 쿼리가 단순하다는 장점이 있다.

 

단점은 예를 들어 Album의 경우에는 Artist만 존재하기 때문에 나머지 속성에 대해서는 null이 들어가야하고 null이 허용된다는 단점이 존재한다. 또한 하나의 테이블에 모든 정보를 저장하기 때문에 테이블이 커질 수 있다. 임계치를 넘어서는 등의 상황에 따라서 조회 성능이 오히려 느려질 수는 있지만 이런 경우는 흔하지 않긴하다.

 

 

 

3. 구현 클래스 각각의 테이블 전략

 

이는 테이블을 나누지도 하나의 테이블에도 하지 않는 그냥 단순히 테이블을 다 나눠버리는 전략이다. 쓰면 안된다. 장점은 서브 타입을 명확하게 구분해서 처리할 때 효과적이고 not null이 가능하다는 장점이 있지만, 치명적인 단점으로는 자식테이블을 함께 조회할 때 성능이 느리다. 이게 무슨 말이냐면 find로 찾을때 Item.class 라던지 부모 클래스를 통해서 조회할 수 있어야하는데, 조회할때 다 뒤져봐야한다.(union all 쿼리가 나감..) 객체지향스럽지도 않고 데이터베이스 관점으로도 올바르지 않다. 또한 자식 테이블을 통합해서 쿼리하기도 어렵다. 

 

가능하면 지양하자.