Spring/Spring 기초 및 세팅

Spring day 6

seungwon-1 2026. 6. 23. 14:12

Spring day 6

[Spring 입문 6일차] JPA와 @Entity — 객체를 그대로 DB에 저장하기

들어가며

5일차에서 계층을 Controller, Service, Repository로 나누고, 회원을 일단 메모리(Map)에 저장하는 리포지토리를 만들어 봤다. 동작은 했지만 한 가지 한계가 분명했다. 프로그램을 껐다 켜면 데이터가 전부 사라진다. 메모리는 임시 보관함일 뿐이니까.

그래서 오늘은 진짜 데이터베이스를 붙였다. 그리고 그 과정에서 처음으로 JPA를 만났다. 솔직히 말하면, 메모리 리포지토리를 손으로 짤 때보다 코드가 더 줄어드는 걸 보고 좀 놀랐다.

1. JPA가 뭔가

DB에 데이터를 넣고 빼려면 원래는 SQL을 직접 써야 한다. INSERT INTO member ..., SELECT * FROM member WHERE ... 이런 식으로. 회원 하나 저장하려고 SQL을 일일이 적는 건 생각보다 번거롭다.

JPA(Java Persistence API)는 이 일을 대신해 준다. 자바 객체를 DB 테이블에 자동으로 연결(매핑)해 주는 기술이다. 내가 member 객체를 저장하라고 하면, JPA가 알아서 그에 맞는 SQL을 만들어 DB에 날린다. SQL을 직접 안 써도 되는 게 핵심이다.

처음엔 "마법처럼 알아서 된다"는 게 오히려 불안했는데, 결국 JPA도 내부에서 SQL을 만들어 실행하는 것뿐이라는 걸 알고 나니 마음이 좀 놓였다.

2. @Entity — 이 객체는 테이블이다

JPA에게 "이 클래스는 DB 테이블과 연결할 거야"라고 알려주는 게 @Entity다. 회원 클래스에 붙여봤다.

@Entity
public class Member {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    // getter, setter 생략
}
  • @Entity — 이 클래스를 DB 테이블과 매핑한다. 클래스 이름 Member가 곧 테이블 member가 된다.
  • @Id — 이 필드가 테이블의 기본 키(Primary Key)다. 각 행을 구분하는 고유 번호.
  • @GeneratedValue — id 값을 DB가 자동으로 채워준다. 내가 직접 번호를 안 매겨도 된다.

클래스 하나에 어노테이션 세 개를 붙였을 뿐인데, 이게 곧 테이블 설계가 됐다. 객체와 테이블의 경계가 흐려지는 느낌이 신기했다.

3. Repository가 더 단순해졌다

5일차엔 save, findById를 직접 구현했다. JPA를 쓰면 그것마저 줄어든다. Spring Data JPA가 제공하는 인터페이스를 상속하기만 하면 된다.

public interface MemberRepository extends JpaRepository<Member, Long> {
}

이게 끝이다. 구현 클래스를 안 만들어도 save(), findById(), findAll(), delete() 같은 기본 메서드가 이미 들어있다. 인터페이스만 선언하면 Spring이 구현체를 알아서 만들어 빈으로 등록해 준다. 5일차에 메모리 구현체를 직접 짜던 걸 떠올리면, 코드량 차이가 꽤 크다.

여기서 5일차의 교훈이 다시 빛났다. 서비스는 여전히 MemberRepository 인터페이스에만 의존한다. 그래서 안쪽 구현이 메모리에서 JPA로 통째로 바뀌었는데도 서비스 코드는 손댈 게 없었다. 계층을 나누고 인터페이스로 약속을 잡아둔 보람이 여기서 나왔다.

4. DB 설정 (H2)

세팅 때 넣어둔 H2 Database를 연결했다. application.properties에 몇 줄만 적으면 된다.

spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:testdb
spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true
  • h2.console.enabled — 브라우저에서 DB를 직접 들여다볼 수 있는 콘솔을 켠다. (/h2-console)
  • ddl-auto=create — 앱을 켤 때 엔티티를 보고 테이블을 자동으로 만들어 준다.
  • show-sql=true — JPA가 실제로 날리는 SQL을 콘솔에 찍어준다.

show-sql을 켜두니, 내가 save() 한 번 부를 때 JPA가 insert into member ... 쿼리를 만들어 실행하는 게 콘솔에 그대로 보였다. "마법"의 정체를 눈으로 확인하는 순간이라 이게 제일 재밌었다.

5. 오늘의 정리

  • 메모리 저장은 앱을 끄면 사라진다. 그래서 진짜 DB가 필요하다.
  • JPA는 자바 객체를 DB 테이블에 매핑해, SQL을 직접 안 써도 데이터를 저장/조회하게 해준다.
  • @Entity / @Id / @GeneratedValue로 클래스를 테이블로 만든다.
  • JpaRepository를 상속하면 기본 CRUD 메서드가 공짜로 따라온다.
  • 구현이 메모리 → JPA로 바뀌어도, 인터페이스에 의존한 덕분에 서비스는 그대로였다.

5일차엔 "층을 왜 나누나"가 와닿지 않았는데, 오늘 구현체를 통째로 갈아끼우면서 그 답을 몸으로 느꼈다. 이제 데이터가 진짜로 남는다. 다음엔 이걸 가지고 게시글 CRUD를 직접 만들어볼 차례다.

'Spring > Spring 기초 및 세팅' 카테고리의 다른 글

Spring day 5  (0) 2026.06.22
Spring day 4  (0) 2026.06.21
Spring day 3  (0) 2026.06.20
Spring day 2  (0) 2026.06.19
Spring day 1  (0) 2026.06.17