1. 들어가며
많은 백엔드 개발자들이 JPA부터 배우기 시작한다.
Entity 클래스를 만들고, 어노테이션을 붙이면
쿼리 없이도 데이터가 저장되고 조회되는 걸 보고 이렇게 생각한다.
“와, JPA가 다 해주네.”
하지만 실무에 들어가면, 바로 벽에 부딪힌다.
- 쿼리가 왜 여러 번 나가는지,
- @OneToMany에서 insert가 왜 두 번 나가는지,
- select 한 번 날렸을 뿐인데 콘솔에 수십 줄의 쿼리가 찍히는 이유까지.
도무지 이해가 되지 않는다.
JPA는 단순한 기술이 아니다.
관계형 데이터베이스(RDB)라는 견고한 기반 위에서 작동하는 추상화 도구다.
그래서 그 기반을 모르면, 겉으로는 잘 동작해 보여도
조금만 복잡한 상황이 오면 원리도 모르고 쿼리는 쏟아지고, 문제를 해결하지 못한 채 헤매게 된다.
JPA를 제대로 배우기 전에 반드시 알아야 할
데이터베이스의 핵심 개념들을 정리하려고 한다.
2. 데이터베이스는 왜 필요한가?
백엔드 개발을 시작하면 어느 순간부터 데이터와 마주하게 된다.
사용자 정보를 저장하고, 게시글을 불러오고, 주문 내역을 기록해야 하는 순간들이 온다.
그럴 때 처음 떠오르는 건 아마 이런 방식일 것이다.
💾 텍스트 파일로 저장
가장 단순한 방법은 파일로 저장하는 것이다.
사용자 정보를 user.txt 같은 텍스트 파일에 저장해두면 된다.
1, mingking2, mingee641@gmail.com
2, mingi, jmgman86@gmail.com
간단하다. 눈으로도 바로 보인다.
하지만 이런 방식은 금세 한계에 부딪힌다.
“이 중에서 이메일이 @example.com인 사용자만 보여줘”
→ 전부 읽고 문자열로 조건 걸어야 한다.
“가입일 기준으로 정렬해줘”
→ 직접 파싱해서 정렬 로직을 짜야 한다.
“사용자 수가 1만 명이 넘었어”
→ 파일이 너무 커져서 읽는데만 몇 초가 걸린다.
파일은 구조가 없고, 검색과 조건 필터링이 어렵고, 동시 접근도 안 된다.
📊 엑셀로 데이터를 관리
조금 더 나아가면 엑셀을 사용하는 것이다.
표 형태로 데이터를 정리하고, 필터도 걸고, 정렬도 쉽게 할 수 있다.
| 이름 | 이메일 |
| mingking2 | mingee641@gmail.com |
| mingi | jmgman86@gmail.com |
여기까지는 꽤 괜찮다.
하지만 문제는 데이터가 커지고, 여러 명이 동시에 다뤄야 할 때 생긴다.
- 실수로 셀을 지우면 복구가 어렵다.
- 다중 사용자 동시 편집은 충돌을 일으킬 수 있다.
- 수만 건 이상의 데이터를 다루기엔 엑셀이 버거워진다.
즉, 엑셀은 혼자 쓰기엔 좋지만, 협업이나 대용량 작업엔 적합하지 않다.
💡 데이터베이스 등장

이 모든 문제를 해결하기 위해 등장한 게 바로 데이터베이스(Database)다.
- 데이터를 정형화된 구조(테이블)로 저장하고
- 원하는 조건으로 빠르고 정확하게 조회할 수 있으며
- 여러 사람이 동시에 접근해도 데이터가 꼬이지 않도록 관리해준다.
게다가 트랜잭션, 제약조건, 권한 설정 등…
단순한 저장소를 넘어 데이터의 신뢰성과 보안, 정합성까지 보장해준다.
3. RDB와 NoSQL
개발을 하다 보면 데이터를 저장할 수 있는 여러 가지 방식이 등장한다.
그중에서도 대표적인 방식이 바로 RDB(Relational Database)와 NoSQL이다.

처음에는 “둘 다 데이터를 저장한다”는 점에서 비슷해 보이지만,
실제로는 철학부터 사용 목적까지 완전히 다르다.
🧱 RDB (Relational Database)
RDB는 우리가 흔히 아는 MySQL, PostgreSQL, Oracle 같은 데이터베이스다.
모든 데이터를 테이블(표) 형태로 저장한다.
게시글 테이블 (posts)
| id | title | content | user_id |
|----|-------------|--------------|---------|
| 1 | 첫 글입니다 | 반가워요~ | 3 |
| 2 | 공지사항 | 오늘부터~ | 1 |
기본 구조
- 행(Row): 한 건의 데이터
- 열(Column): 속성(컬럼)
- 데이터를 다룰 때는 SQL을 사용
✅ 장점
- 데이터 구조가 정확하게 설계됨 -> 무결성 보장
- 중복 데이터가 적고, 변경 시 일관성 유지가 용이함
- 복잡한 조건의 쿼리 조합, 조인, 필터링에 강함
- 트랜잭션 관리가 뛰어남 (ACID 지원)
❌ 단점
- 스키마(테이블 구조)가 엄격해서 유연성이 낮음
- 데이터 구조가 바뀌면 마이그레이션이 필요
- 수평 확장(서버 늘리기)이 어렵고, 성능 튜닝이 필수인 경우가 많음
🔗 NoSQL
NoSQL은 “Not Only SQL”의 약자다.
SQL 기반의 RDB가 갖는 구조적 제약을 넘기 위해 등장한 데이터 저장 방식이다.
예시: MongoDB, Redis, Cassandra, DynamoDB 등
RDB처럼 “표”로 저장하지 않고, 더 다양한 방식으로 데이터를 저장한다.
| 형태 | 예시 |
| 문서(Document) 기반 | MongoDB |
| 키-값(Key-Value) | Redis |
| 그래프 구조 | Neo4j |
| Wide-column | Cassandra |
✅ 장점
- 스키마가 없다 → 유연한 데이터 구조 설계 가능
- 구조가 바뀌어도 자유롭게 저장 가능
- 수평 확장이 쉬워서 대용량/분산 환경에 적합
- 속도가 빠름 (캐시 서버 등에서 강력함)
❌ 단점
- 데이터 중복이 많을 수 있음
- 트랜잭션 보장이 약함 → 정합성이 중요한 시스템엔 불안
- 표준 쿼리가 없고, DB마다 문법이 달라 러닝 커브가 존재
❓ 언제 무엇을 써야 할까?
✅ RDB가 유리한 경우
- 데이터 구조가 명확하고 안정적할 때
- 사용자, 게시글, 주문 정보처럼 정합성이 중요한 데이터
- 복잡한 조회 조건이나 JOIN이 자주 필요한 경우
✅ NoSQL이 유리한 경우
- 구조가 유동적이고 자주 바뀌는 데이터
- 빅데이터, 로그, 캐시, 세션 정보
- 빠른 읽기/쓰기 속도가 중요한 시스템
📌 수직 확장 vs 수평 확장?
수직 확장 (Vertical Scaling): 한 대의 서버 성능을 업그레이드 (ex. 더 좋은 CPU, 더 많은 RAM)
수평 확장 (Horizontal Scaling): 서버를 여러 대로 나눠 부하 분산 (ex. 노드 추가)
🧱 RDB는 강한 정합성을 지켜야 해서 여러 서버에 나누기 어렵다.
→ 그래서 주로 수직 확장을 선택한다.
🔗 NoSQL은 데이터 정합성보다는 확장성과 속도를 우선시한다.
→ 그래서 수평 확장이 매우 쉽고, 자연스럽다.
이번 시리즈에서는 JPA를 사용하므로,
기반이 되는 관계형 데이터베이스(RDB)를 사용한다.
4. 데이터 모델링과 ERD
개발을 하다 보면 “데이터를 어떻게 저장할지”는 늘 중요한 문제다.
어떤 테이블이 있어야 하고, 어떤 관계로 연결되어야 하는지를 미리 설계하는 과정이 바로 데이터 모델링이다.
이 과정은 다음과 같은 단계로 진행된다:
- 요구사항 분석 – 어떤 데이터를 저장해야 할지 파악
- 개념적 설계 – 엔티티(Entity)와 관계를 ERD로 시각화
- 논리적 설계 – 속성(Attribute), 제약조건, 키 등을 정리
- 물리적 설계 – 실제 데이터베이스 테이블로 구현
이 개념들은 본문에서는 간략히 소개하고, 자세한 설명은 아래 링크에서 확인하길 추천한다:
👉 📋 데이터 모델링 개념 & ERD 다이어그램 작성 💯 총정리 (INPA 블로그)
📋 데이터 모델링 개념 & ERD 다이어그램 작성 💯 총정리
데이터 모델링 이란? 데이터 모델링이란 정보시스템 구축의 대상이 되는 업무 내용을 분석하여 이해하고 약속된 표기법에 의해 표현하는걸 의미한다. 그리고 이렇게 분석된 모델을 가지고 실제
inpa.tistory.com
5. 테이블 간 관계와 매핑
모델링을 할 때 가장 중요한 건 “테이블 간의 관계를 어떻게 표현하느냐”다.
객체지향에서는 객체를 필드로 참조하면 되지만,
관계형 데이터베이스에서는 Foreign Key(FK)를 통해 관계를 맺는다.
📚 관계 종류
✅ 1:1 (One-to-One)
- 한 명의 학생은 딱 하나의 주민등록번호만 가진다.
- 두 테이블 간에 정확히 1:1 매칭이 이루어지는 구조다.
- 예: User ↔ UserProfile
✅ 1:N 또는 N:1 (One-to-Many / Many-to-One)
- 하나의 회원이 여러 개의 게시글을 작성할 수 있다.
- 반대로, 하나의 게시글은 하나의 작성자만 가진다.
- 일반적인 게시판 구조에서 매우 자주 등장
이 경우, 게시글 테이블에 user_id라는 FK를 둔다.
즉, “다수 테이블”이 FK를 가짐 → 다 쪽에 외래키가 존재
✅ N:M (Many-to-Many)
- 여러 명의 학생이 여러 개의 수업을 들을 수 있다.
- 관계 테이블이 필요하다. 예: student_course 테이블
실무에서는 대부분 중간 테이블을 만들어 1:N + N:1로 풀어냄
예: students(id) ↔ student_course(student_id, course_id) ↔ courses(id)
🧩 관계 표현 방식
- PK (Primary Key): 테이블의 고유 식별자
- FK (Foreign Key): 다른 테이블의 PK를 참조하는 열
예를 들어 게시판의 post 테이블은 user_id를 외래키로 가져야 user 테이블과 연결된다.
CREATE TABLE post (
id BIGINT PRIMARY KEY,
user_id BIGINT,
title VARCHAR(255),
FOREIGN KEY (user_id) REFERENCES user(id)
);
📌 관계선 기호 정리
ERD에서 관계를 시각적으로 나타낼 때는 다음과 같은 기호를 사용한다:
| 기호 | 의미 |
| ○ | 없어도 된다 (optional) |
| | | 정확히 하나 (1개만 가능) |
| ∈ (까마귀발) | 여러 개 (N) 가능 |
🔎 식별 관계 vs 비식별 관계
✅ 식별 관계 (Identifying Relationship)
-> 자식 테이블이 부모 테이블의 PK를 그대로 자신의 PK로 삼는 경우
예시: 주문(Order)과 주문 상세(OrderDetail)
Order
- order_id (PK)
OrderDetail
- order_id (PK, FK)
- product_id (PK)
- quantity
✅ 비식별 관계 (Non-Identifying Relationship)
-> 자식 테이블이 부모 테이블의 PK를 참조(FK)만 할 뿐, 자신의 PK로 사용하지 않는 경우
예시: 사용자(User)와 게시글(Post)
User
- id (PK)
Post
- id (PK)
- user_id (FK)
- title
JPA에서는 식별 관계를 표현하려면
- @EmbeddedId나 @IdClass를 써야 하고,
- equals/hashCode 구현도 신경 써야 해서 복잡하고 오류 가능성 높음
그래서 실무에서는 가능하면 비식별 관계 + 단일 기본키 사용을 선호한다.
6. SQL(Structured Query Language)
백엔드 애플리케이션에서 데이터는 항상 중심에 있다.
사용자 정보 저장, 게시글 조회, 주문 처리 등 모든 흐름의 핵심은 데이터를 어떻게 다룰 것인가이다.
이때 사용하는 것이 바로 SQL(Structured Query Language)이며,
이는 관계형 데이터베이스(RDBMS)에서 데이터를 정의하고 조작하기 위한 표준 언어다.
SQL은 크게 다음 세 가지 목적에 따라 분류된다.
🧱 DDL (Data Definition Language) – 데이터 구조 정의
DDL은 테이블, 컬럼, 제약조건 등 데이터베이스의 스키마 구조를 정의하거나 변경할 때 사용한다.
| 명령어 | 설명 |
| CREATE | 테이블, 데이터베이스, 인덱스 등을 생성 |
| ALTER | 기존 테이블이나 컬럼을 수정 |
| DROP | 테이블, 인덱스 등을 삭제 |
| TRUNCATE | 테이블의 모든 데이터를 삭제 (구조는 유지) |
CREATE TABLE user (
id BIGINT PRIMARY KEY,
username VARCHAR(50) NOT NULL,
password VARCHAR(255),
email VARCHAR(100)
);
🛠 DML (Data Manipulation Language) – 데이터 조작
DML은 데이터베이스 안에 존재하는 데이터 자체를 삽입, 조회, 수정, 삭제하는 데 사용된다.
애플리케이션에서 가장 빈번하게 사용되는 영역이다.
| 명령어 | 설명 |
| SELECT | 데이터 조회 |
| INSERT | 새로운 데이터 삽입 |
| UPDATE | 기존 데이터 수정 |
| DELETE | 데이터 삭제 |
-- 데이터 삽입
INSERT INTO user (id, username, email)
VALUES (1, 'daeyoung', 'dy@example.com');
-- 조건부 조회
SELECT username, email FROM user WHERE id = 1;
-- 데이터 수정
UPDATE user SET email = 'new@example.com' WHERE id = 1;
-- 데이터 삭제
DELETE FROM user WHERE id = 1;
🔐 DCL (Data Control Language) – 권한 및 트랜잭션 제어
DCL은 주로 접근 권한 설정이나 트랜잭션의 처리 결과를 확정하거나 취소할 때 사용된다.
| 명령어 | 설명 |
| GRANT, REVOKE | 사용자 권한 부여 및 회수 |
| COMMIT | 트랜잭션 작업을 확정하여 반영 |
| ROLLBACK | 트랜잭션 작업을 취소하고 이전 상태로 되돌림 |
BEGIN;
UPDATE account SET balance = balance - 10000 WHERE id = 1;
UPDATE account SET balance = balance + 10000 WHERE id = 2;
COMMIT; -- 두 작업을 모두 반영
-- 또는 ROLLBACK; -- 둘 다 취소
🔗 JOIN – 테이블 간 관계 기반 조회
SQL의 강력한 기능 중 하나는 테이블 간 조인이다.
JOIN을 활용하면 외래 키를 기준으로 여러 테이블의 데이터를 결합해 하나의 결과로 조회할 수 있다.
예시: 게시글과 작성자 이름 함께 조회
SELECT post.title, user.username
FROM post
JOIN user ON post.user_id = user.id;
7. 트랜잭션과 ACID
데이터베이스에서 여러 작업을 처리하다 보면, 다음과 같은 일이 자주 발생한다:
“사용자 A의 계좌에서 10,000원을 출금하고,
사용자 B의 계좌에 10,000원을 입금해야 한다.”
이때 하나만 성공하고, 다른 하나가 실패하면?
→ 돈이 사라지거나, 두 번 지급될 수도 있다.
→ 데이터의 신뢰성이 무너진다.
이런 상황을 안전하게 처리하기 위한 최소 단위가 바로 트랜잭션(Transaction)이다.
✅ 트랜잭션
트랜잭션은 데이터베이스에서 일어나는 하나의 논리적 작업 단위다.
여러 작업이 하나의 트랜잭션에 묶이면, 모두 성공하거나 전부 실패해야 한다.
즉, 트랜잭션은 “모두 아니면 아무것도”라는 원칙을 지킨다.
✅ ACID: 트랜잭션이 지켜야 할 4가지 원칙
ACID는 데이터베이스 트랜잭션이 정합성 있고 신뢰성 있게 처리되도록 보장하는 특성이다.
| 속성 | 의미 | 설명 |
| A - Atomicity (원자성) | all or nothing | 트랜잭션 내 작업은 전부 수행되거나, 하나도 수행되지 않아야 한다. |
| C - Consistency (일관성) | before → after | 트랜잭션 전후로 데이터는 항상 유효한 상태여야 한다. 제약조건을 위반하면 실패. |
| I - Isolation (격리성) | 독립성 보장 | 동시에 실행되는 트랜잭션이 서로 영향을 주지 않도록 분리되어야 한다. |
| D - Durability (지속성) | 결과 보존 | 트랜잭션이 커밋되면 그 결과는 영구히 저장된다. 장애가 나도 사라지지 않음. |
🧪 예시: 송금 트랜잭션
BEGIN;
UPDATE account SET balance = balance - 10000 WHERE id = 1;
UPDATE account SET balance = balance + 10000 WHERE id = 2;
COMMIT;
- 두 작업이 모두 성공하면 COMMIT
- 하나라도 실패하면 ROLLBACK으로 되돌림
-> 여기서의 BEGIN ~ COMMIT 전체가 하나의 트랜잭션이다.
8. 결론
지금까지 JPA를 배우기 전에 반드시 알아야 할 관계형 데이터베이스의 핵심 개념들을 정리해봤다.
- 데이터는 왜 단순 파일이나 엑셀로는 부족한지
- RDB와 NoSQL은 어떻게 다르고, 어떤 기준으로 선택해야 하는지
- 테이블과 관계는 어떻게 설계되고
- SQL은 어떤 구조로 데이터를 조작하며
- 트랜잭션은 어떻게 정합성을 보장하는지
이 내용들은 JPA를 이해하는 데 있어 단순한 배경지식이 아니라, 실제 동작 원리와 성능 이슈를 판단하는 기준이 된다.
JPA를 제대로 쓰기 위해선, 그 내부에서 어떤 쿼리가 언제, 왜 실행되는지를 이해해야 한다.
그리고 그 출발점은 지금까지 정리한 데이터베이스의 기본기다.
다음 글에서는 JPA의 가장 근본적인 오해와 마주한다. 바로, “객체와 테이블은 왜 그렇게 다르게 움직이는가?”
👉 2025.04.13 - [DB 모르는 백엔드 탈출기] - [DB 모르는 백엔드 탈출기 Ep.2] 테이블은 객체가 아니다.
[DB 모르는 백엔드 탈출기 Ep.2] 테이블은 객체가 아니다.
1. 들어가며JPA를 쓰면 객체만 잘 설계하면 DB도 잘 작동할 줄 알았다.User와 Post를 양방향으로 참조하고,@OneToMany, @ManyToOne을 붙이면 자바 객체처럼 자유롭게 탐색하고 저장할 수 있을 줄 알았다.
mingking2.tistory.com
'DB 모르는 백엔드 탈출기' 카테고리의 다른 글
| [DB 모르는 백엔드 탈출기 Ep.4] 연관관계 주인은 누가 되어야 할까? (0) | 2025.04.16 |
|---|---|
| [DB 모르는 백엔드 탈출기 Ep.3] JPA는 객체를 어떻게 관리할까? (0) | 2025.04.14 |
| [DB 모르는 백엔드 탈출기 Ep.2] 테이블은 객체가 아니다. (1) | 2025.04.13 |
| [DB 모르는 백엔드 탈출기 Ep.0] JPA가 다 해주는 거 아니었나요? (0) | 2025.04.12 |
