URECA 과정을 진행하면서 해당강의를 중심으로 스터디를 진행하고 있다.
spring에 대해 1도 모르는 상태였기 때문에 개념정리를 목표로 시작했고, 현재 Spring과 JPA(1~7강)까지 정리한 상태이다.
복기를 위해 하나의 단원이 끝날 때마다 스터디 진행중에 논란?이 되었던 주제, 정확히 설명하지 못하는 주제에 대해 다시한번 정리하기로 했다.
JPA를 통해 Java로 데이터를 모델링 할 수 있음
ORM : 자바 필드 → DB 테이블
원래라면 DB에 데이터 테이블을 만들고, 이에 대해 데이터 관계를 이해해서 java 필드를 만들게 된다.
하지만, JPA를 이용해서 자바만 이용하여 DB에 접근하고, 데이터를 사용할 수 있다.
이 과정에서 필요한건, DB와 OOP의 불일치 해결이다.
- DB는 테이블 내 attribute에 다른 테이블을 넣을 수 없다. 그래서 테이블끼리의 관계를 FK를 통해 표현한다.
- OOP는 class의 필드에 다른 class 타입을 생성할 수 있다. 또한 상속관계가 있다.
이 두개를 해결해야만 OOP에서 작성한 코드로 DB에 데이터를 CRUD하고 관리 할 수 있다.
JPA의 상속 구조
JPA는 OOP의 상속 구조를 DB테이블에 매핑(매칭)하기 위해 3가지 방법을 사용한다.
단일 테이블 전략 (Single Table Strategy)
: 모든 상속관계에 있는 entity를 하나의 테이블(단일 테이블)에 만든다.
OOP에서라면 서로 다른 class를 통해 구분되던 entity들이 하나의 테이블에 정리되다 보니 구분자를 이용해서 각 entity 타입을 구분한다.
Vehicle
-------------------------
| id | dtype | manufacturer | numberOfDoors | loadCapacity |
-------------------------
| 1 | CAR | Toyota | 4 | NULL |
| 2 | TRUCK | Ford | NULL | 3000 |
-------------------------
이런 DB가 있다면,
import javax.persistence.*;
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "dtype")
public abstract class Vehicle {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String manufacturer;
}
@Entity
@DiscriminatorValue("CAR")
public class Car extends Vehicle {
private int numberOfDoors;
}
@Entity
@DiscriminatorValue("TRUCK")
public class Truck extends Vehicle {
private int loadCapacity;
}
이런 코드로 만들 수 있다.
- @Inheritance(strategy = InheritanceType.SINGLE_TABLE) : 해당 annotation 으로 단일 테이블 전략을 사용한다고 명시
- @DiscriminatorColumn(name = "dtype") : 해당 annotation으로 구분자 컬럼을 정의
- @DiscriminatorValue("TRUCK") : 이런식으로 dtype을 정의해줄 수 있다.
조인 테이블 전략 (Joined Table Strategy)
: 다른 클래스와 차별되는 entity는 각각의 테이블(하위 클래스)에 저장하고, 공통적인 entity는 새로운 테이블(상위 클래스)에 저장 후, PK를 사용해서 상위 테이블과 하위 테이블을 join한다.
개인적으로 상속과 가장 비슷한 방법인것 같다.
- 중복되는 entity는 상위 테이블에 몰아넣고, 개별적인 entity는 각각의 테이블에 저장
- OOP의 extends 를 대신해서 PK를 통한 상위 테이블과 하위 테이블의 join
다만, 상위 테이블과 하위 테이블 사이에 join이 발생하므로, join에 의한 성능 문제가 발생할 수 있다.
+----+--------------+
| id | manufacturer |
+----+--------------+
| 1 | Toyota |
| 2 | Ford |
+----+--------------+
+----+--------------+
| id | numberOfDoors|
+----+--------------+
| 1 | 4 |
+----+--------------+
+----+--------------+
| id | loadCapacity |
+----+--------------+
| 2 | 3000 |
+----+--------------+
이런 DB가 있다면,
+---------------------+
| Vehicle |
+---------------------+
| id (PK) |
| manufacturer |
+---------------------+
|
|
FK
|
|
+---------------------+ +---------------------+
| Car | | Truck |
+---------------------+ +---------------------+
| id (PK, FK) | | id (PK, FK) |
| numberOfDoors | | loadCapacity |
+---------------------+ +---------------------+
DB의 구조는 이렇게 되고,
import javax.persistence.*;
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Vehicle {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String manufacturer;
}
@Entity
public class Car extends Vehicle {
private int numberOfDoors;
}
@Entity
public class Truck extends Vehicle {
private int loadCapacity;
}
이런 코드로 만들 수 있다.
- @Inheritance(strategy = InheritanceType.JOINED) : 해당 annotation 으로 조인 테이블 전략을 사용한다고 명시
- @GeneratedValue(strategy = GenerationType.IDENTITY) : PK를 자동으로 생성해주는 annotation으로, 여기서는 바로 밑에 작성된 id가 PK가 된다.
구체 클래스 전략 (Table per Class Strategy)
: 각각의 테이블에 필요한 모든 entity를 저장
조인 테이블 전략은 중복되는 entity를 상위테이블에 저장했다면, 구체 클래스는 중복되는 entity도 각각의 테이블에 저장한다.
Java로 치면, 상속받은 상위 클래스의 필드를 상위클래스를 없애고 각각의 하위 클래스들에 필드를 만들어주는 느낌
즉, 테이블은 1개 줄었지만, 각각의 테이블에 entity가 늘었고, 데이터 중복의 위험이 생길 수 있다.
Car
-----------------------
| id | manufacturer | numberOfDoors |
-----------------------
| 1 | Toyota | 4 |
-----------------------
Truck
-----------------------
| id | manufacturer | loadCapacity |
-----------------------
| 2 | Ford | 3000 |
-----------------------
이런 DB가 있다면,
import javax.persistence.*;
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Vehicle {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String manufacturer;
}
@Entity
public class Car extends Vehicle {
private int numberOfDoors;
}
@Entity
public class Truck extends Vehicle {
private int loadCapacity;
}
이런 코드로 만들 수 있다.
- @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) : 해당 annotation 으로 구체 클래스 전략을 사용한다고 명시
- Java 자체에서는 extends로 상속받을 수 있으므로 굳이 중복되는 필드를 2번 사용하지 않았다.
- 즉, 조인 테이블 전략과 구체 클래스 전략은 코드상 @Inheritance 를 통해 구분된다.
'하고싶은거 > Springboot' 카테고리의 다른 글
API_정의, 명세 (0) | 2024.08.04 |
---|---|
SpringBoot 동작 원리 (0) | 2024.07.22 |
Entity 생명주기 (0) | 2024.06.28 |
JPA vs Spring data JPA (0) | 2024.06.28 |
#개발 #게임 #일상
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!