Files
spring-boot-examples/docs/jpa/04_JPA 생명주기와 영속성 컨텍스트.md
2025-04-08 19:56:24 +09:00

139 lines
6.2 KiB
Markdown

아래는 "JPA 생명주기와 영속성 컨텍스트"에 대해 설명하는 글입니다. 예시를 포함하되, 롬복은 사용하지 않고 명확한 이해를 돕기 위해 기본적인 코드 스타일을 유지했습니다.
---
### JPA 생명주기와 영속성 컨텍스트
JPA에서 엔티티는 특정한 생명주기를 거치며 관리됩니다. 이 생명주기는 영속성 컨텍스트(Persistence Context)라는 JPA의 핵심 개념과 밀접하게 연관되어 있습니다. 영속성 컨텍스트는 엔티티의 상태를 추적하고 관리하며, 데이터베이스와의 동기화를 담당하는 환경입니다. 이를 통해 JPA는 객체와 데이터베이스 간의 매핑을 효율적으로 처리합니다.
#### 영속성 컨텍스트란?
영속성 컨텍스트는 엔티티 매니저(EntityManager)가 엔티티를 관리하는 논리적인 공간입니다. 엔티티가 영속성 컨텍스트에 포함되면 JPA가 해당 엔티티의 상태를 추적하고, 트랜잭션이 커밋될 때 데이터베이스에 반영합니다. 주요 특징은 다음과 같습니다:
- **1차 캐시**: 조회한 엔티티를 메모리에 저장해 동일 트랜잭션 내에서 재사용 가능.
- **변경 감지(Dirty Checking)**: 엔티티의 변경 사항을 자동으로 감지해 SQL을 생성.
- **쓰기 지연(Write Behind)**: 트랜잭션 커밋 시점에 변경 사항을 한꺼번에 데이터베이스에 반영.
#### 엔티티 생명주기
엔티티는 네 가지 상태를 거칩니다:
1. **비영속(Transient)**
- 엔티티 객체가 생성되었지만, 영속성 컨텍스트나 데이터베이스와 연결되지 않은 상태.
- JPA가 전혀 관리하지 않음.
2. **영속(Managed)**
- 영속성 컨텍스트에 의해 관리되는 상태.
- `persist()``find()` 메서드로 엔티티가 영속성 컨텍스트에 포함됨.
3. **준영속(Detached)**
- 영속성 컨텍스트에서 분리된 상태.
- `detach()``close()`로 인해 더 이상 관리되지 않음.
4. **삭제(Removed)**
- 영속성 컨텍스트와 데이터베이스에서 삭제되도록 예약된 상태.
- `remove()` 호출 후 트랜잭션 커밋 시 삭제됨.
#### 생명주기 예시
아래는 `Book` 엔티티를 통해 생명주기를 설명하는 코드입니다.
```java
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
@Entity
public class Book {
@Id
private Long id;
private String title;
public Book() {} // JPA 기본 생성자 요구
public Book(Long id, String title) {
this.id = id;
this.title = title;
}
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
}
```
```java
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;
public class JpaLifecycleExample {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpaExample");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
// 1. 비영속 상태
Book book = new Book(1L, "JPA 기초");
System.out.println("상태: 비영속");
// 2. 영속 상태
em.persist(book);
System.out.println("상태: 영속");
// 영속성 컨텍스트에서 동일 객체 재사용 (1차 캐시)
Book foundBook = em.find(Book.class, 1L);
System.out.println("동일 객체: " + (book == foundBook)); // true
// 변경 감지
book.setTitle("JPA 심화"); // 별도 update 호출 없이 변경 감지됨
// 3. 삭제 상태
em.remove(book);
System.out.println("상태: 삭제 예약");
// 트랜잭션 커밋 - 데이터베이스 반영
em.getTransaction().commit();
System.out.println("커밋 완료");
// 4. 준영속 상태
em.detach(book); // 이미 삭제되었으므로 효과 없음
em.close();
// 새로운 트랜잭션에서 준영속 상태 확인
EntityManager em2 = emf.createEntityManager();
em2.getTransaction().begin();
book.setTitle("JPA 고급"); // 영속성 컨텍스트가 없으므로 반영 안 됨
em2.getTransaction().commit();
em2.close();
emf.close();
}
}
```
#### 코드 설명
1. **비영속 상태**
- `Book book = new Book(1L, "JPA 기초");`: 객체는 생성되었지만 JPA와 무관합니다.
2. **영속 상태**
- `em.persist(book)`: 영속성 컨텍스트에 포함되며, 1차 캐시에 저장됩니다.
- `em.find(Book.class, 1L)`: 데이터베이스 조회 없이 캐시에서 반환됩니다.
3. **변경 감지**
- `book.setTitle("JPA 심화")`: 영속 상태의 엔티티는 변경이 감지되어 커밋 시 자동으로 `UPDATE` 쿼리가 실행됩니다.
4. **삭제 상태**
- `em.remove(book)`: 엔티티가 삭제 예약되며, 커밋 시 `DELETE` 쿼리가 실행됩니다.
5. **준영속 상태**
- `em.detach(book)` 또는 `em.close()`: 영속성 컨텍스트에서 분리되어 더 이상 관리되지 않습니다.
#### 영속성 컨텍스트의 이점
- **성능 향상**: 1차 캐시로 동일 트랜잭션 내 반복 조회를 줄임.
- **자동 동기화**: 변경 감지로 개발자가 직접 SQL을 작성할 필요 없음.
- **트랜잭션 보장**: 쓰기 지연으로 트랜잭션 내 변경을 일괄 처리.
#### 주의사항
- 영속성 컨텍스트는 트랜잭션 범위에 따라 생명주기가 달라집니다. 트랜잭션이 끝나면 컨텍스트도 종료됩니다(기본적으로).
- 준영속 상태의 엔티티는 변경 감지가 적용되지 않으므로, 필요 시 `merge()`로 다시 영속 상태로 전환해야 합니다.
---
JPA의 생명주기와 영속성 컨텍스트는 엔티티 관리의 핵심입니다. 이를 이해하면 데이터베이스 작업을 더 효율적으로 처리할 수 있습니다. 다음 장에서는 트랜잭션 관리와 실무 활용을 다뤄보겠습니다.
---
책의 흐름에 맞는지, 추가 예시나 설명이 필요하면 말씀해 주세요!