DevBoi

[고급 매핑] 상속관계 매핑 본문

Develop/[JPA]

[고급 매핑] 상속관계 매핑

HiSmith 2022. 1. 18. 17:08
반응형

자바나 객체는 상속관계가 존재하지만, 관계형 디비에는 해당 상속관계가 존재하지 않는다.

쉽게 말하면 상속관계 매핑은, 객체의 상속관계를  디비의 슈퍼타입 서브타입으로 매핑하는 것을 의미한다.

 

 

참고로 슈퍼타입 서브타입에 대해서는 별도 포스팅으로 진행하겠다.

무튼 이렇게 상속 관계 에 있을때 jpa 엔티티 설게를 다음 과 같이 했다고 가정한다.

 

뭐 굳이 코멘트가 필요 없을 정도이지만, 무튼 Movie라는 엔티티가 있고

뮤직과 북이 이 무비를 상속 받아서, 엔티티를 한다고 가정하자, 이대로 구동하면 디비 테이블 설계 쿼리는 아래와 같이 나간다.

 

Hibernate: create table movie (dtype varchar(31) not null, id bigint not null, name varchar(255), book_name varchar(255), music_name varchar(255), primary key (id))

 

한마디로, movie라는 엔티티에 상속 받는 녀석의 모든 컬럼값이 때려박혀서 들어가게 된다.

이렇게 되는 이유는 JPA의 디폴트 설정인 단일 테이블 전략으로 설정이 되어있기 때문에 이렇게 테이블이 설계된다.

 

상속의 주체가 되는 슈퍼부모 ㅋㅋ 무튼 부모 엔티티의 상속 전략을 Joined로 바꿔보자

그러면 테이블 쿼리는 이렇게 나가게 된다;

Hibernate: create table movie (id bigint not null, name varchar(255), primary key (id))

Hibernate: create table music (music_name varchar(255), id bigint not null, primary key (id))

Hibernate: create table book (book_name varchar(255), id bigint not null, primary key (id))

 

즉 모든 엔티티별로 테이블이 생성이 되고, 해당 공통으로 상속 하는 id에 대한 value가 별도 컬럼으로 생성되어있고, 다른컬럼들은 해당

엔티티에 맞는 컬럼들로 생성이 된다.

 

테스트 용도로 한번 Book의 데이터를 만들어서 jpa를 통해서 insert해보자

movie를 상속 받은 book은 아래와 같이 넣으면,

요로케 자동으로 상속 하는 테이블 두개에 insert가 되는 것을 확인 할수 있다.

 

 

이렇게 조인 되는 객체의 것도 찾아서 find 후 사용할수도 있게 된다.

flush, clear는 참고로 해당 1차 캐시에서 날리고 새로 받은 것이다.

이렇게 호출하게되면 정상적으로 값을 가져올수 있게되고 jpa에서는 자동으로 조인 쿼리까지 만들어준다.

Hibernate: select book0_.id as id1_9_0_, book0_1_.name as name2_9_0_, book0_.bookname as bookname1_0_0_ from book book0_ inner join movie book0_1_ on book0_.id=book0_1_.id where book0_.id=?

 

 

추가로 이렇게 조인을 많이하는 경우에는

해당 속성을 줄수있다. 해당 속성을 걸게되면

이런식으로 자식에 대한 객체가 많을때, 어떤 자식의 요소 때문에 이 부모의 테이블에 값이 삽입이 되었는지를 알수있다.

name을 추가속성으로 주면 DYTPE말고 다른 이름으로 바뀌게 된다.

 

또한 자식의 엔티티에서 discrimatorValue로 하게되면, Entity name을 변경하여 저장하듯이

엔티티 명이아닌 다른값으로 넣을수 있다. 에를 들면 Dtype의 값에 Book말고 다른값이들어갈수있다.

 

테이블과 엔티티의 전략은 아래와 같고, 여러가지의 방법으로 할수있다.

 

 

위에서 본 단일 테이블 전략은 그냥 한테이블에 다 때려박고, Dtype으로만 구분을 하는것이다.

굳이 여러 테이블을 사용할 필요가 없는 경우에 유용할듯하다.

 

오히려 객체는 여러개로 필요하지만, 테이블은 하나로 관리되는게 유용할때 좋은 전략이다.

 

 

구현 클래스마다 테이블 전략은 부모 객체를 추상 클래스로 만들고

하위에서 구현하는 객체로 만들면, 부모에 대한 클래스는 테이블을 설계하지 않고,

자식에 대한 클래스만 생성이 되는 것이다.

 

즉 부모에 대한 엔티티는 테이블로 생성하지 않고, 자바의 개념처럼 하위 자식들만 테이블이 생성되고, 관리된다고 보면된다

이 전략은 비효율적이다.

 

왜냐면 부모의 타입으로 조회를 할떄 자식 타입을 다 select 로 조회를 하기 때문이다.

 

 

1. 조인 전략 (정석 적인 전략)

장점

- 정규화가 되어있다.

- 제약조건을 다 같은 곳에서 걸어서 싱크를 맞출수있다.

- 외래키 참조 무결성 제약조건을 활용 가능하다. (특정 공통의 분류를 통해 조회를 할때 하위 테이블을 다 조회하지 않아도 된다.)

- 저장 공간이 효율적으로 된다.

 

단점 

- 조회할때 join이 많아 성능 다운

- 조회 쿼리 복잡하다

- insert 할때 쿼리가 2번 나간다.

 

 

2. 단일 테이블 전략

장점

- 조회 쿼리가 단순하고 성능이 좋다.

- 자식 엔티티 중 매핑이 아닌 컬럼은 null을 모두 허용해야함

- 한테이블이 커질수 있고, 상황에 따라 성능이 더 저하될 수 있다.

 

3. 구현 클래스 마다 전략 (안쓰는게 좋은 전략)

장점

-not null 제약조건을 따로 사용가능

-서브 타입간의 구분을 명확하게 지을수 있다.

 

단점

- 여러 테이블을 (통합된 자식 테이블) 조회할때 union으로 다 찾아야 하고

- 신규로 형식이 추가되면 다 고쳐야한다.

 

 

반응형