RDBMS 설계와 JPA 설계의 차이 AI 답변
전통적인 RDBMS 설계와 JPA 에 맞는 설계는 차이가 있을까요?
좋은 질문입니다. 실제로 두 관점이 꽤 다른 곳들이 있고, 지금까지 진행하신 Team-Member-Hobby-Job 설계에서 이미 이 차이들을 자연스럽게 마주치고 계셨습니다. 정리해드릴게요.
1. 설계의 출발점 자체가 다릅니다
전통적 RDBMS 설계 | JPA 설계 | |
|---|---|---|
출발점 | 정규화(Normalization) — 데이터 중복을 없애는 것이 최우선 | 도메인 모델 — 객체 간 협력과 행위가 자연스러운 것이 최우선 |
사고 방식 | "이 데이터를 어떤 테이블에 나눠 저장해야 하는가" | "이 개념을 어떤 객체로 표현하고, 객체끼리 어떻게 관계 맺어야 하는가" |
관계의 의미 | 테이블 간 참조(FK)는 그저 데이터 정합성 도구 | 관계(연관관계)는 객체 그래프 탐색의 통로 |
DB 설계자는 "3정규형까지 맞췄는가"를 먼저 고민하지만, JPA/객체지향 설계자는 "이 엔티티가 다른 엔티티를 알아야 할 이유가 있는가"를 먼저 고민합니다. 방금 Job을 두고 나누신 고민(양방향으로 할지 말지)이 정확히 이 관점 차이에서 나온 겁니다 — 순수 DB 관점에서는 FK만 있으면 그만이지만, 객체 관점에서는 "탐색 방향이 실제로 필요한가"가 기준이 됩니다.
2. 연관관계의 "방향"이라는 개념 자체가 RDBMS엔 없습니다
RDBMS에서 FK는 그냥 컬럼입니다. member.team_id가 있으면, SQL에서는 team → member로도, member → team으로도 자유롭게 조인할 수 있습니다. 방향이라는 개념이 없습니다.
하지만 JPA 객체 그래프에서는 방향이 실재하는 제약입니다.
java
member.getTeam(); // 가능 (단방향이어도 OK)
team.getMembers(); // Team에 컬렉션 필드가 없으면 불가능그래서 "연관관계의 주인" 같은, RDBMS에는 없는 개념이 JPA에만 존재합니다. 지난번 Team-Member에서 배우신 "주인만 외래키에 반영된다"는 규칙이 바로 이 차이에서 나옵니다.
3. 식별자(Key) 전략의 차이
전통적 RDBMS: 자연키(Natural Key)를 선호하는 경향이 있었습니다. 예: 주민등록번호, 이메일, 학번처럼 "업무적으로 의미 있는 값"을 PK로 쓰는 경우.
JPA: 대리키(Surrogate Key, 예: 자동증가 id)를 강력히 권장합니다. 이유는:
자연키는 나중에 바뀔 수 있음 (이메일 변경, 정책 변경 등) → PK가 바뀌면 모든 FK도 연쇄적으로 바뀌어야 함
영속성 컨텍스트가 엔티티를
(타입, PK)로 식별하는데, PK가 의미를 가지면 이 식별 체계가 취약해짐
지금 프로젝트에서 @GeneratedValue(strategy = GenerationType.IDENTITY)로 전부 대리키를 쓰고 계신 게 바로 이 원칙을 따르고 계신 겁니다.
4. 참조 방식: FK 컬럼 값 vs 객체 참조
이게 방금 Job 질문에서 정확히 부딪히신 지점입니다.
sql
-- RDBMS 관점: job_id는 그냥 정수 컬럼
SELECT * FROM job_of_member WHERE job_id = 3;java
// JPA 관점: job은 실제 Job 객체
Job job = jobOfMember.getJob();
String name = job.getJobName(); // 값을 통째로 들고 있음RDBMS 설계자에게 job_id bigint는 아무 문제 없는 정상 설계입니다. 하지만 JPA/객체지향 관점에서는 "의미 있는 개념을 원시 타입(Long)으로 표현하는 것"을 좋지 않게 봅니다 (이를 Primitive Obsession이라 부르기도 합니다). 그래서 @ManyToOne으로 감싸서 실제 객체로 다루길 권장하는 겁니다 — 이게 아까 제가 단방향 @ManyToOne을 추천드린 이유이기도 합니다.
5. N:M 관계를 다루는 방식
RDBMS: 중간(연결) 테이블은 그냥 당연한 설계입니다. member_hobby(member_id, hobby_id) 처럼 FK 두 개만 있어도 충분합니다.
JPA: @ManyToMany를 직접 쓸 수도 있지만, 실무에선 지양합니다. 이전에 HobbyOfMember를 만드셨던 이유가 바로 이겁니다 — 연결 테이블에 input_date 같은 관계 자체의 속성을 붙이고 싶어지는 순간, @ManyToMany로는 표현이 안 됩니다. RDBMS 설계자에게 연결 테이블은 그냥 하나의 테이블일 뿐이지만, JPA에서는 "연결 테이블도 엔티티로 승격시킬지" 자체가 설계 결정 포인트입니다.
6. 값 타입(Value Object) 개념
RDBMS에는 없는, JPA만의 개념입니다. 예를 들어 주소를 표현할 때:
sql
-- RDBMS: 그냥 컬럼 여러 개
CREATE TABLE member (
...
address_city varchar(50),
address_street varchar(100),
address_zipcode varchar(10)
);java
// JPA: @Embeddable로 값 타입 객체를 만들어 재사용
@Embeddable
public class Address {
private String city;
private String street;
private String zipcode;
}
@Entity
public class Member {
@Embedded
private Address address; // 테이블 컬럼은 그대로지만, 객체는 하나로 묶임
}테이블 구조(컬럼)는 동일하지만, 자바 객체 입장에서는 "주소"라는 개념을 하나의 응집된 단위로 다룰 수 있습니다. 이건 순수 RDBMS 설계엔 없는 사고방식입니다.
7. 상속(Inheritance) 개념
RDBMS는 상속이라는 개념 자체가 없습니다 (테이블은 상속 못 합니다). 하지만 자바 객체는 상속이 자연스럽죠. 그래서 JPA는 이 간극을 메우기 위해 별도 전략을 제공합니다.
@MappedSuperclass— 지금BaseEntity에서 쓰신 방식 (테이블화 안 됨, 컬럼만 상속)SINGLE_TABLE,JOINED,TABLE_PER_CLASS— 진짜 엔티티 상속(예:Member를 상속받는VipMember) 시 테이블을 어떻게 나눌지 정하는 전략 (이전에 다음 학습 주제로 안내드렸던 부분입니다)
이런 전략 자체가 "객체는 상속이 되는데 테이블은 안 된다"는 근본적 간극(Object-Relational Impedance Mismatch)에서 나온 JPA만의 해법입니다.
8. 성능 최적화 관점의 차이
RDBMS 설계자: 인덱스, 쿼리 실행 계획, 조인 전략을 SQL 레벨에서 직접 고민합니다.
JPA 개발자: SQL을 직접 안 짜는 대신, 지연 로딩 전략, 영속성 컨텍스트 캐시, N+1 문제처럼 JPA 고유의 성능 이슈를 이해해야 합니다. 지난번 배우신 N+1 문제가 대표적인데, 이건 순수 SQL만 짜는 사람은 절대 마주치지 않는 문제입니다 (SQL은 짠 그대로 실행되니까요). JPA는 "객체 그래프를 편하게 탐색하게 해주는 대가"로 이런 새로운 종류의 함정을 만듭니다.
요약
구분 | RDBMS 중심 사고 | JPA/객체 중심 사고 |
|---|---|---|
최우선 가치 | 정규화, 데이터 무결성 | 객체 그래프의 자연스러움 |
관계 | 방향 없음, FK는 그냥 컬럼 | 방향 있음, 연관관계의 주인 개념 |
식별자 | 자연키도 허용 | 대리키 강력 권장 |
참조값 | 원시 타입(FK 컬럼값)으로 충분 | 가능하면 객체 참조로 승격 |
N:M | 연결 테이블이면 끝 | 연결 테이블도 엔티티로 승격할지 고민 |
값 묶음 | 컬럼 여러 개로 충분 |
|
상속 | 개념 자체가 없음 | 여러 매핑 전략 필요 |
성능 이슈 | 쿼리/인덱스 최적화 | + 지연로딩, N+1, 캐시 이해 필요 |
실무에서 좋은 JPA 설계자는 이 두 관점을 다 이해하고, 상황에 맞게 저울질합니다. 아까 Job 설계에서 "DB 무결성이 중요하면 FK 매핑, 정말 단순 코드값이면 원시 필드"라고 말씀드린 것도 이 저울질의 한 예시입니다.
