[DB 모르는 백엔드 탈출기 Ep.1] JPA 쓰기 전에 꼭 알아야 할 DB 기초

2025. 4. 13. 03:35·DB 모르는 백엔드 탈출기

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

개발을 하다 보면 “데이터를 어떻게 저장할지”는 늘 중요한 문제다.

어떤 테이블이 있어야 하고, 어떤 관계로 연결되어야 하는지를 미리 설계하는 과정이 바로 데이터 모델링이다.

 

이 과정은 다음과 같은 단계로 진행된다:

  1. 요구사항 분석 – 어떤 데이터를 저장해야 할지 파악
  2. 개념적 설계 – 엔티티(Entity)와 관계를 ERD로 시각화
  3. 논리적 설계 – 속성(Attribute), 제약조건, 키 등을 정리
  4. 물리적 설계 – 실제 데이터베이스 테이블로 구현

 

이 개념들은 본문에서는 간략히 소개하고, 자세한 설명은 아래 링크에서 확인하길 추천한다:
👉 📋 데이터 모델링 개념 & 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
'DB 모르는 백엔드 탈출기' 카테고리의 다른 글
  • [DB 모르는 백엔드 탈출기 Ep.4] 연관관계 주인은 누가 되어야 할까?
  • [DB 모르는 백엔드 탈출기 Ep.3] JPA는 객체를 어떻게 관리할까?
  • [DB 모르는 백엔드 탈출기 Ep.2] 테이블은 객체가 아니다.
  • [DB 모르는 백엔드 탈출기 Ep.0] JPA가 다 해주는 거 아니었나요?
mingking2
mingking2
에러와 삽질 속에서 성장하는 응애 개발자의 성장 일지
  • mingking2
    Mingking의 삽질 기록
    mingking2
  • 전체
    오늘
    어제
    • 분류 전체보기 (19)
      • 삽질로그 (10)
      • 스타트업 응애기 (1)
      • 프로젝트 도전기 (2)
      • DB 모르는 백엔드 탈출기 (5)
      • 네트워크 (1)
  • 블로그 메뉴

    • 홈
    • 태그
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    server
    Async
    servlet
    CompletableFuture
    JPA
    RDB
    orm
    n:m
    Java
    WebSocket
    플로우차트
    DB
    Sync
    batch
    MVC
    context
    @JoinColumn
    연관관계
    Tomcat
    spring
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
mingking2
[DB 모르는 백엔드 탈출기 Ep.1] JPA 쓰기 전에 꼭 알아야 할 DB 기초
상단으로

티스토리툴바