아래는 "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의 생명주기와 영속성 컨텍스트는 엔티티 관리의 핵심입니다. 이를 이해하면 데이터베이스 작업을 더 효율적으로 처리할 수 있습니다. 다음 장에서는 트랜잭션 관리와 실무 활용을 다뤄보겠습니다. --- 책의 흐름에 맞는지, 추가 예시나 설명이 필요하면 말씀해 주세요!