|
| 1 | +# 개요 |
| 2 | + |
| 3 | +상속관계 매핑에 대해서 헷갈리는 감이 없지 않아서 이 참에 정리해보자는 마음이 생겨서 정리합니다. |
| 4 | + |
| 5 | +# JPA 상속관계 매핑 |
| 6 | + |
| 7 | +JPA에는 상속관계 매핑을 위한 여러 에너테이션이 존재합니다. 이에 대해 알아봅시다! |
| 8 | + |
| 9 | +### `@Inheritance(strategy=InheritanceType.XXX)` |
| 10 | + |
| 11 | +상속 관계 매핑을 위해서 부모 엔티티에 `@Inheritance` 에너테이션을 붙여주고 자식 엔티티에 `extends`를 이용해 상속받음을 표시하면, 부모 엔티티의 멤버를 자식 엔티티에도 적용할 수 있습니다. |
| 12 | + |
| 13 | +이는 `"상속 전략"`이라는 것에 따라 pk, fk를 어떻게 하고 테이블 구조를 어떻게 가져가는지 달라지게 됩니다. |
| 14 | + |
| 15 | +```java |
| 16 | + |
| 17 | +// Item.class |
| 18 | + |
| 19 | +@Entity |
| 20 | +@Inheritance(strategy = InheritanceType.SINGLE_TABLE) // 기본 전략 SINGLE_TABLE |
| 21 | +public class Item{ |
| 22 | + @Id |
| 23 | + @GeneratedValue(strategy = GenerationType.IDENTITY) |
| 24 | + private Long id; |
| 25 | + |
| 26 | + private String name; |
| 27 | + private int price; |
| 28 | + |
| 29 | + public Item(String name, int price) { |
| 30 | + this.id = id; |
| 31 | + this.name = name; |
| 32 | + this.price = price; |
| 33 | + } |
| 34 | +} |
| 35 | + |
| 36 | + |
| 37 | +// Book.class |
| 38 | + |
| 39 | +@Entity |
| 40 | +public class Book extends Item { |
| 41 | + |
| 42 | + private String author; |
| 43 | + private String isbn; |
| 44 | + |
| 45 | + public Book(String name, int price, String author, String isbn) { |
| 46 | + super(name, price); |
| 47 | + this.author = author; |
| 48 | + this.isbn = isbn; |
| 49 | + } |
| 50 | +} |
| 51 | + |
| 52 | + |
| 53 | +``` |
| 54 | + |
| 55 | +# 상속 전략 |
| 56 | + |
| 57 | +### JOINED: 조인 전략 |
| 58 | + |
| 59 | +각각 테이블로 변환 |
| 60 | + |
| 61 | +장점 |
| 62 | + |
| 63 | +- 데이터가 정규화 되어 있음 |
| 64 | +- 외래 키 참조 무결성 제약조건을 활용할 수 있다. |
| 65 | +- 저장공간 효율화 |
| 66 | + |
| 67 | +단점 |
| 68 | + |
| 69 | +- 조회 시 조인을 많이 사용 -> 성능 저하 |
| 70 | +- 조회 쿼리가 복잡함 |
| 71 | +- 데이터 저장 시 INSERT 2번 호출 |
| 72 | + |
| 73 | +### SINGLE_TABLE: 단일 테이블 전략 |
| 74 | + |
| 75 | +통합 테이블 |
| 76 | + |
| 77 | +장점 |
| 78 | + |
| 79 | +- 조인이 필요없음 -> 조회 성능 빠름 |
| 80 | +- 테이블이 하나라서 조회 쿼리가 단순함 |
| 81 | + |
| 82 | +단점 |
| 83 | + |
| 84 | +- 자식 엔티티가 매핑한 컬럼은 모두 null 허용 -> 데이터 무결성 관점에서 애매함 |
| 85 | +- 단일 테이블에 모든 것을 저장하므로 테이블이 커지면 성능 저하 |
| 86 | + |
| 87 | +### TABLE_PER_CLASS: 구현 클래스마다 테이블 전략 |
| 88 | + |
| 89 | +서브 타입 테이블로 변환 |
| 90 | + |
| 91 | +- 이건 안 쓰는 게 좋음 |
| 92 | + |
| 93 | +장점 |
| 94 | + |
| 95 | +- 서브 타입 명확하게 구분해서 처리 시 효과적 |
| 96 | +- not null 제약조건 사용 가능 |
| 97 | + |
| 98 | +단점 |
| 99 | + |
| 100 | +- 여러 자식 테이블을 함께 조회할 때 성능 저하 (UNION 써야함) |
| 101 | +- 자식 테이블을 통합해서 쿼리하기 어려움 |
| 102 | + |
| 103 | +## 관련 에너테이션 |
| 104 | + |
| 105 | +## `@DiscriminatorColumn(name = "DTYPE")` |
| 106 | + |
| 107 | +- 부모 테이블에 자식 TYPE에 대한 컬럼 명을 변경할 수 있음 |
| 108 | +- 기본 값 = "DTYPE" |
| 109 | + |
| 110 | +## `@DiscriminatorValue("XXX")` |
| 111 | + |
| 112 | +- 자식 엔티티에 선언 시 부모 테이블의 DTYPE 컬럼에 어떤 내용으로 기록될 지 정할 수 있음 |
| 113 | +- 기본 값 = 엔티티 클래스 명 |
| 114 | +- DTYPE = Movie -> MovieItem 등으로 변경 가능 |
| 115 | + |
| 116 | +# 공통 매핑 정보 관리 |
| 117 | + |
| 118 | +공통 속성(createdDate, updatedDate 등)이 많아서 코드의 중복이 발생할 때 공통 매핑 정보를 편리하게 관리하는 방법이 존재합니다. |
| 119 | + |
| 120 | +## `@MappedSuperClass` |
| 121 | + |
| 122 | +```java |
| 123 | +// BaseTimeEntity.class |
| 124 | + |
| 125 | +@MappedSuperclass |
| 126 | +public abstract class BaseTimeEntity { |
| 127 | + private LocalDateTime createdDate; |
| 128 | + private LocalDateTime lastModifiedDate; |
| 129 | +} |
| 130 | + |
| 131 | + |
| 132 | +// Item.class |
| 133 | + |
| 134 | +public class Item extends BaseTimeEntity{ |
| 135 | + @Id |
| 136 | + @GeneratedValue(strategy = GenerationType.IDENTITY) |
| 137 | + private Long id; |
| 138 | + |
| 139 | + private String name; |
| 140 | + private int price; |
| 141 | + |
| 142 | + public Item(String name, int price) { |
| 143 | + this.id = id; |
| 144 | + this.name = name; |
| 145 | + this.price = price; |
| 146 | + } |
| 147 | +} |
| 148 | +``` |
| 149 | + |
| 150 | +# 참고 |
| 151 | + |
| 152 | +[김영한님 자바 ORM 표준 JPA 프로그래밍 - 기본편](https://inf.run/pe5D) |
0 commit comments