RECENT POSTS

최근에 작성한 글

01 / 03

전체 글

전체 보기

[TIL] Spring Boot 입문(3) - Entity부터 Query Method까지

오늘은 JPA의 핵심 개념인 Entity, 영속성 컨텍스트, Entity 상태 변화, Spring Data JPA, Auditing, Query Method에 대해 학습했다. 이전에 JDBC와 JPA가 왜 필요한지 이해했다면, 오늘은 JPA가 내부적으로 어떻게 동작하는지 살펴보는 시간이었다.


1. Entity란?

Entity는 JPA가 관리하는 객체이다.

일반 Java 객체와 달리 데이터베이스의 테이블과 매핑되어 JPA의 관리 대상이 된다.

@Entity
@Table(name = "memo")
public class Memo {

    @Id
    private Long id;

    private String username;

    private String contents;
}

특징

  • DB 테이블과 1:1 매핑
  • JPA가 객체 생명주기를 관리
  • 객체 중심으로 DB 작업 가능

즉,

Memo 객체
↓
JPA
↓
memo 테이블

형태로 동작한다.


2. 영속성 컨텍스트(Persistence Context)

JPA의 핵심 기능이다.

영속성 컨텍스트는 Entity를 효율적으로 관리하기 위한 공간이다.

Entity
 ↓
Persistence Context
 ↓
Database

개발자가 Entity를 저장하거나 조회하면 JPA는 먼저 영속성 컨텍스트에서 작업을 수행한다.

EntityManager

영속성 컨텍스트를 조작하는 관리자

EntityManager em;

주요 기능

em.persist();
em.find();
em.remove();

EntityManagerFactory

EntityManager를 생성하는 공장

EntityManagerFactory emf;

보통 애플리케이션당 하나만 생성된다.


3. JPA와 트랜잭션

JPA는 영속성 컨텍스트에 저장했다고 바로 DB에 반영하지 않는다.

em.persist(memo);

↓

영속성 컨텍스트 저장

↓

transaction.commit();

↓

실제 SQL 실행

장점

  • SQL 여러 개를 한 번에 처리
  • 실패 시 전체 롤백
  • 데이터 무결성 보장

JPA는 변경 사항을 모아두었다가 Commit 시점에 DB에 반영한다.


4. 영속성 컨텍스트의 기능

1차 캐시

영속성 컨텍스트 내부에는 캐시가 존재한다.

Memo memo = em.find(Memo.class, 1L);

처음 조회

DB 조회
↓
1차 캐시 저장
↓
객체 반환

두 번째 조회

Memo memo2 = em.find(Memo.class, 1L);
1차 캐시 조회
↓
DB 접근 없음

즉 같은 트랜잭션 내에서는 성능 향상을 기대할 수 있다.


5. Entity의 상태

JPA에서는 Entity가 여러 상태를 가진다.

비영속 (Transient)

Memo memo = new Memo();

단순 객체

JPA 관리 X

영속 (Managed)

em.persist(memo);
JPA 관리 O

변경 감지 가능


준영속 (Detached)

em.detach(memo);

영속성 컨텍스트에서 분리

JPA 관리 X

변경 감지 불가능


삭제 (Removed)

em.remove(memo);

삭제 예정 상태

commit 시 DELETE

핵심

Transient
 ↓ persist
Managed
 ↓ detach
Detached
 ↓ merge
Managed
 ↓ remove
Removed

JPA 면접에서도 자주 등장하는 개념이다.


6. Spring Boot에서 JPA 사용하기

Spring Boot는 EntityManager와 EntityManagerFactory를 자동으로 생성한다.

의존성 추가

implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

application.properties

spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.format_sql=true

ddl-auto 옵션

옵션설명

create 테이블 재생성
create-drop 종료 시 삭제
update 변경사항 반영
validate 검증만 수행
none 아무것도 안함

실무에서는 주로

local : update
production : validate

방식을 사용한다.


7. @Transactional

Spring에서는 트랜잭션을 매우 쉽게 적용할 수 있다.

@Transactional
public void createMemo() {

}

동작 방식

메서드 시작
↓
트랜잭션 시작
↓
DB 작업
↓
성공 → Commit
실패 → Rollback

readOnly 옵션

@Transactional(readOnly = true)

조회 전용

  • 성능 최적화
  • 수정 시 예외 발생

조회용 서비스에서는 적극적으로 사용해야 한다.


8. Spring Data JPA

JPA를 더 쉽게 사용하도록 만든 모듈이다.

가장 큰 특징은 Repository 인터페이스만 작성하면 구현체를 자동 생성해준다.

Repository

public interface MemoRepository
        extends JpaRepository<Memo, Long> {

}

제네릭 의미

JpaRepository<Memo, Long>
  • Memo → Entity
  • Long → PK 타입

Spring이 자동으로 구현체를 생성하여 Bean으로 등록한다.


9. JpaRepository 주요 메서드

저장

memoRepository.save(memo);

전체 조회

memoRepository.findAll();

단건 조회

memoRepository.findById(id);

삭제

memoRepository.delete(memo);

CRUD 대부분을 직접 구현하지 않아도 된다.


10. JPA Auditing

게시글, 댓글, 회원 정보에는 보통 생성일과 수정일이 필요하다.

매번 직접 넣는 것은 비효율적이다.

Timestamped

@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class Timestamped {

    @CreatedDate
    private LocalDateTime createdAt;

    @LastModifiedDate
    private LocalDateTime modifiedAt;
}

사용

public class Memo extends Timestamped {

}

설정

@EnableJpaAuditing

결과

createdAt
modifiedAt

자동 생성 및 자동 수정된다.


11. Query Method

Spring Data JPA의 가장 강력한 기능 중 하나이다.

메서드 이름만으로 SQL을 생성한다.

예시

List<Memo> findAllByUsername(String username);

↓

SELECT *
FROM memo
WHERE username = ?

최신순 정렬

List<Memo> findAllByOrderByModifiedAtDesc();

↓

SELECT *
FROM memo
ORDER BY modified_at DESC;

구현 없이 메서드 선언만으로 SQL이 생성된다.


오늘은 JPA를 단순히 사용하는 수준이 아니라 내부 동작 원리를 이해하는 데 집중했다.

특히 영속성 컨텍스트 → 1차 캐시 → Entity 상태 → 트랜잭션 → Spring Data JPA 로 이어지는 흐름이 연결되면서 JPA가 왜 생산성을 높여주는지 이해할 수 있었다.

이전까지는 save(), findAll()을 그냥 사용했지만 이제는 내부에서 EntityManager, 영속성 컨텍스트, 트랜잭션이 어떻게 동작하는지 어느 정도 설명할 수 있게 되었다.