스프링 핵심 원리 - 기본편 - 인프런
스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다. 초급 프레임워크 및 라이브러리 웹 개발 서버 개발 Back-End Spring 객체지향 온
www.inflearn.com
강의를 들으며 생각 정리 + "자바 ORM 표준 JPA 프로그래밍" 책 참고
상속 관계 매핑
관계형 데이터베이스에는 객체지향 언어에서 다루는 상속이라는 개념이 없다. 비슷한 개념으로 슈퍼타입, 서브타입 관계라는 모델링 기법이 있다. 상속 관계 매핑이라는 것은 객체의 상속 구조와 데이터베이스의 슈퍼타입, 서브타입 관계를 매핑하는 것을 말한다.
객체의 상속 구조에서 부모 클래스는 @Inheritence(strategy = [전략]) 애노테이션을 붙여서 상속 관계 매핑 전략을 설정한다.
조인 전략
@Inheritance(strategy = InheritanceType.JOINED)
조인 전략은 엔티티 각각을 모두 테이블로 만들고 자식 테이블이 부모 테이블의 기본 키를 받아서 기본 키+외래 키로 사용하는 전략이다.
따라서 자식 엔티티를 데이터베이스에 저장할 때, 부모 엔티티의 속성도 같이 저장해줘야 하기 때문에 insert 쿼리가 두 번 생긴다. 조회할 때는 부모 엔티티와 조인해서 조회한다.
주의할 점이 있는데 객체는 타입으로 구분할 수 있지만 테이블은 타입의 개념이 없다. 따라서 타입을 구분하는 컬럼을 추가해야 한다. 부모 엔티티에 @DiscriminatorColumn 애노테이션을 붙이면 DTYPE이 부모 테이블에 저장되고 이곳에 자식 클래스 명이 저장된다.(default) 자식 엔티티에 대한 DTYPE 값을 사용자 지정하고 싶다면 @DiscriminatorValue을 자식 엔티티에 붙여 타입명을 변경할 수 있다.
+) 추가로 자식 테이블은 부모 테이블의 PK 컬럼명을 그대로 사용하는데, 만약 자식 테이블의 PK 컬럼명을 변경라고 싶으면 @PrimaryKeyJoinColumn을 사용하면 된다.
장점
- 테이블이 정규화된다.
- 외래 키 참조 무결성 제약조건을 활용할 수 있다. - 외래 키는 참조할 수 없는 값을 가질 수 없음
- 저장공간을 효율적으로 사용한다.
단점
- 조회할 때 조인이 많이 사용되므로 성능이 저하될 수 있다.
- 조회 쿼리가 복잡하다.
- 데이터를 등록할 때 INSERT SQL을 두 번 실행한다.
단일 테이블 전략
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
단일 테이블 전략은 테이블을 하나만(부모 테이블) 사용한다. 그리고 구분 컬럼(DTYPE)으로 어떤 자식 데이터가 저장되었는지 구분한다. 그래서 @DiscriminatorColumn이 없어도 자동으로 테이블에 DTYPE을 설정한다. 조회할 때 조인을 사용하지 않으므로 일반적으로 가장 빠르다.
주의할 점은 자식 엔티티가 매핑한 컬럼은 모두 null을 허용해야 한다는 점이다. 어떤 자식 엔티티를 저장했다면 또 다른 자식 엔티티에 대한 컬럼은 따로 저장되지 않기 때문이다.
장점
- 조인이 필요 없으므로 일반적으로 조회 성능이 빠르다.
- 조회 쿼리가 단순하다.
단점
- 자식 엔티티가 매핑한 컬럼은 모두 null을 허용해야 한다.
- 단일 테이블에 모든 것을 저장하므로 테이블이 커질 수 있다. 그러므로 상황에 따라서는 조회 성능이 오히려 느려질 수 있다.
구현 클래스마다 테이블 전략
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
구현 클래스마다 테이블 전략은 자식 엔티티마다 테이블을 만든다. 그리고 자식 테이블 부모 엔티티의 속성 등 필요한 컬럼이 모두 있다. 이 때, 부모 클래스를 추상 클래스로 지정해야 한다. 깔끔해 보이지만 만약 부모 타입으로 조회를 한다면 부모의 PK로 모든 자식 테이블들을 뒤져봐야 하기 때문에 비효율적이다. 일반적으로 추천하지 않는 전략이다
장점
- 서브 타입을 구분해서 처리할 때 효과적이다.
- not null 제약조건을 사용할 수 있다.
단점
- 여러 자식 테이블을 함께 조회할 때 성능이 느리다.
- 자식 테이블을 통합해서 쿼리하기 어렵다.
-> 조인이나 단일 테이블 전략을 각 상황에 알맞게 사용하자. 단순한 구조면 단일 테이블 전략이 좋고 점점 복잡해져서 객체 지향적인 관리가 필요하다면 조인 전략을 사용하자.
@Mapped Superclass - 매핑 정보 상속
@MappedSuperclass는 각 클래스마다 공통 정보가 필요할 때 사용한다.
지금까지의 상속 관계 매핑은 부모 클래스와 자식 클래스를 모두 데이터베이스 테이블과 매핑했다. @MappedSuperclass를 사용해서 상속받은 자식클래스의 매핑정보만 제공할 수 있다.
@MappedSuperclass
public abstract class BaseEntity {
private String createdBy;
private LocalDateTime createdDate;
private String lastModifiedBy;
private LocalDateTime lastModifiedDate;
//Getter, Setter
}
BaseEntitiy 클래스가 @MappedSuperclass를 사용할 때, 위 클래스를 상속 받은 클래스들은 BaseEntity 클래스의 속성을 사용할 수 있다. 다만 매핑 시 BaseEntity의 테이블은 생성하지 않는다.
위처럼 등록일자, 수정일자, 등록자, 수정자 같은 여러 엔티티에서 공통으로 사용하는 속성을 효과적으로 관리할 수 있다.
+) 참고로 엔티티(@Entity)는 같은 엔티티이거나, @MappedSuperclass로 지정한 클래스만 상속받을 수 있다.
실전 예제 4 - 상속관계 매핑
공부한 예제를 깃허브에 등록한다.
코드 작성 시 배운 점
상속관계 매핑같은 경우는 단순한 상황에서 객체 지향적 개발을 위해 사용하다가 테이블 수가 많아지는 등 너무 복잡해지면 테이블을 단순화 시키는 것이 좋다.
'java > jpa' 카테고리의 다른 글
[JPA] 값 타입 (0) | 2021.02.02 |
---|---|
[JPA] 프록시와 연관관계 관리 (0) | 2021.01.29 |
[JPA] 다양한 연관관계 매핑 (0) | 2021.01.27 |
[JPA] 연관관계 매핑 기초 (0) | 2021.01.26 |
[JPA] 엔티티 매핑 (0) | 2021.01.22 |