영속성 컨텍스트 (Persistence Context)
- JPA를 이해하는데 가장 중요한 용어
- “엔티티를 영구 저장하는 환경”이라는 뜻
- EntityManager.persist(entity); - 엔티티를 영속성 컨텍스트 라는 곳에 저장
- 영속성 컨텍스트는 논리적인 개념
- 눈에 보이지 않는다.
- 엔티티 매니저를 통해서 영속성 컨텍스트에 접근
엔티티의 생명주기
- 비영속 (Transient)
// 엔티티 객체를 생성한 상태 (비영속) Member member = new Member(); member.setId(1L); member.setUsername("회원1"); // 이 상태에서는 JPA와 전혀 관계가 없습니다.
- 영속성 컨텍스트와 무관한 상태. 단순 객체로 메모리에만 존재합니다.
- 영속 (Managed)
EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); tx.begin(); // 트랜잭션 시작 // 엔티티 객체 생성 Member member = new Member(); member.setId(1L); member.setUsername("회원1"); // 영속성 컨텍스트에 저장 em.persist(member); // 영속 상태로 전환 System.out.println("Persist 완료"); // 영속성 컨텍스트에서 조회 Member findMember = em.find(Member.class, 1L); System.out.println(findMember.getUsername()); // "회원1" tx.commit(); // 트랜잭션 커밋 em.close();
- 영속성 컨텍스트에 저장된 상태. 영속성 컨텍스트가 객체를 관리하며, 변경 감지 및 데이터베이스 동기화를 지원합니다.
- 준영속 (Detached)
EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); tx.begin(); // 영속 상태로 저장 Member member = em.find(Member.class, 1L); // 준영속 상태로 전환 em.detach(member); // 특정 객체만 준영속 상태로 전환 System.out.println("detach 완료"); // 준영속 상태에서는 변경 사항이 반영되지 않음 member.setUsername("변경된 이름"); // 트랜잭션 커밋 (변경 사항 미반영) tx.commit(); em.close();
- 영속성 컨텍스트에서 분리된 상태로, 더 이상 관리되지 않습니다. 데이터베이스 동기화 및 변경 감지가 불가능합니다.
- 삭제 (Removed)데이터베이스에서 제거된 상태. 영속성 컨텍스트에서도 삭제된 상태로 표시됩니다.
-
EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); tx.begin(); // 엔티티 조회 후 삭제 Member member = em.find(Member.class, 1L); em.remove(member); // 삭제 상태로 전환 System.out.println("remove 완료"); tx.commit(); // 데이터베이스에서 삭제 em.close();
영속성 컨텍스트의 주요 이점
1. 1차 캐시
엔티티를 영속성 컨텍스트 내부 캐시에 저장하여, 동일한 데이터에 대한 데이터베이스 호출을 최소화합니다.
Member member1 = em.find(Member.class, "id1"); // DB에서 조회
Member member2 = em.find(Member.class, "id1"); // 1차 캐시에서 조회
System.out.println(member1 == member2); // true
2. 동일성(identity) 보장
동일한 트랜잭션 안에서 같은 키로 조회한 엔티티는 항상 같은 객체로 보장됩니다.
3. 트랜잭션을 지원하는 쓰기 지연
- 변경된 데이터를 즉시 데이터베이스에 반영하지 않고, SQL을 모아서 트랜잭션 종료 시 한 번에 실행합니다.
-
em.persist(member1); // SQL을 데이터베이스에 보내지 않음
em.persist(member2); // SQL을 데이터베이스에 보내지 않음
em.flush(); // SQL 전송
transaction.commit(); // 데이터베이스에 확정
4. 변경 감지 (Dirty Checking)
- 영속성 컨텍스트가 관리하는 엔티티의 변경 사항을 감지하고, 자동으로 SQL을 생성합니다.
- 명시적으로
update()
메서드를 호출하지 않아도 데이터베이스에 반영됩니다.
Member member = em.find(Member.class, "id1");
member.setUsername("변경된 이름"); // 변경 감지
transaction.commit(); // 변경 사항 반영
플러시(Flush)*와 커밋(Commit)
플러시 (Flush)
- 영속성 컨텍스트의 변경 사항을 데이터베이스에 반영.
flush
는 데이터베이스에 변경 사항을 보내지만, 이는 트랜잭션 내부에서만 일어나는 일이므로 해당 트랜잭션이commit
되기 전까지는 다른 사용자가 데이터를 변경하거나 조회할 수 없습니다. 따라서flush
는 실질적으로 데이터베이스와의 동기화를 이루지만, 최종적인 반영은commit
에 의해 확정됩니다. - 이때의 반영은 데이터베이스 레벨에서의 확정이 아닌, 영속성 컨텍스트와 데이터베이스의 동기화에 해당합니다. 그래서 실제로 데이터베이스에 완전히 반영되고 다른 트랜잭션에서 조회 가능하게 되는 것은
commit
을 통해 트랜잭션이 종료될 때입니다. - 트랜잭션은 유지되며, 최종 확정은
commit
에서 이루어집니다. - 자동 호출: JPQL 실행 전, 트랜잭션 커밋 직전 등.
- 명시 호출:
em.flush()
.
커밋 (Commit)
- 트랜잭션의 변경 사항을 영구적으로 확정.
flush()
를 포함하며, 트랜잭션이 종료됩니다.- 롤백 불가 상태가 됩니다.
구분 | flush |
commit |
---|---|---|
데이터베이스 반영 | 변경 사항만 전송, 트랜잭션은 여전히 열려 있음 | 변경 사항을 전송하고, 트랜잭션을 종료함 |
트랜잭션 상태 | 여전히 활성 상태 | 트랜잭션 종료 (커밋 완료) |
롤백 가능 여부 | 가능 | 불가능 (이미 데이터베이스에 영구 반영됨) |
자동 호출 시점 | JPQL, Native Query 실행 전 등 | @Transactional 메서드 종료 시 등 |
준영속 상태
정의
- 엔티티가 영속성 컨텍스트에서 분리된 상태로, 더 이상 JPA가 관리하지 않습니다.
- 데이터베이스와의 동기화 및 변경 감지가 불가능합니다.
전환 방법
em.detach(entity)
특정 엔티티를 준영속 상태로 전환.em.clear()
영속성 컨텍스트를 초기화하여 모든 엔티티를 준영속 상태로 만듭니다.em.close()
영속성 컨텍스트를 종료.
결론
영속성 컨텍스트는 JPA의 핵심으로, 데이터베이스와의 효율적인 상호작용을 위해 다양한 기능을 제공합니다. 특히 1차 캐시, 쓰기 지연, 변경 감지 같은 기능은 성능 최적화와 객체 지향 프로그래밍을 가능하게 합니다. 이미지를 통해 각 개념을 시각적으로 이해하면 실무에 적용하기 더 쉬워질 것입니다.
728x90
'JPA' 카테고리의 다른 글
JPA 프록시, Cascade와 orphanRemoval (0) | 2025.01.22 |
---|