영속성 컨텍스트(Persistence Context)는 JPA (Java Persistence API)를 이해하는 데 핵심적인 개념으로, ORM(Object-Relational Mapping)에서 매우 중요한 역할을 합니다.
영속성 컨텍스트란?
영속성 컨텍스트는 엔티티(Entity) 객체를 영구적으로 저장하는 환경을 의미합니다. 엔티티 매니저(Entity Manager)를 통해 접근할 수 있으며, 애플리케이션 내에서 엔티티 객체를 관리하고 지속성을 보장하는 역할을 합니다.
주요 특징
- 논리적인 개념:
- 영속성 컨텍스트는 물리적으로 존재하는 것이 아니라 논리적으로 존재하는 개념입니다. 실제로는 메모리에 존재하며, 엔티티 매니저를 통해 접근할 수 있습니다.
- 엔티티 관리:
- 영속성 컨텍스트는 엔티티 객체를 관리합니다. 여기에는 엔티티의 상태를 추적하고, 변경 사항을 데이터베이스에 반영하는 역할이 포함됩니다.
- 캐싱 기능:
- 영속성 컨텍스트는 일종의 캐시 역할을 합니다. 한 트랜잭션 내에서 동일한 엔티티를 여러 번 조회하면, 데이터베이스에 매번 접근하는 대신 영속성 컨텍스트 내의 엔티티를 반환합니다. 이를 통해 성능을 최적화할 수 있습니다.
- 변경 감지(Dirty Checking):
- 엔티티 객체의 상태가 변경되면, 영속성 컨텍스트는 이를 감지하고 트랜잭션이 커밋될 때 변경 사항을 데이터베이스에 반영합니다. 이를 통해 자동으로 데이터베이스와의 동기화가 이루어집니다.
영속성 컨텍스트(Persistence Context)에 대한 설명을 추가로 보강해 보겠습니다. 영속성 컨텍스트는 JPA(Java Persistence API)를 이해하는 데 핵심적인 개념으로, ORM(Object-Relational Mapping)에서 매우 중요한 역할을 합니다.
영속성 컨텍스트란?
영속성 컨텍스트는 엔티티(Entity) 객체를 영구적으로 저장하는 환경을 의미합니다. 엔티티 매니저(Entity Manager)를 통해 접근할 수 있으며, 애플리케이션 내에서 엔티티 객체를 관리하고 지속성을 보장하는 역할을 합니다.
주요 특징
- 논리적인 개념:
- 영속성 컨텍스트는 물리적으로 존재하는 것이 아니라 논리적으로 존재하는 개념입니다. 실제로는 메모리에 존재하며, 엔티티 매니저를 통해 접근할 수 있습니다.
- 엔티티 관리:
- 영속성 컨텍스트는 엔티티 객체를 관리합니다. 여기에는 엔티티의 상태를 추적하고, 변경 사항을 데이터베이스에 반영하는 역할이 포함됩니다.
- 캐싱 기능:
- 영속성 컨텍스트는 일종의 캐시 역할을 합니다. 한 트랜잭션 내에서 동일한 엔티티를 여러 번 조회하면, 데이터베이스에 매번 접근하는 대신 영속성 컨텍스트 내의 엔티티를 반환합니다. 이를 통해 성능을 최적화할 수 있습니다.
- 변경 감지(Dirty Checking):
- 엔티티 객체의 상태가 변경되면, 영속성 컨텍스트는 이를 감지하고 트랜잭션이 커밋될 때 변경 사항을 데이터베이스에 반영합니다. 이를 통해 자동으로 데이터베이스와의 동기화가 이루어집니다.
엔티티의 생명주기
엔티티는 다음과 같은 생명주기를 가집니다:

- 비영속(New):
- 영속성 컨텍스트와 전혀 관계가 없는 상태입니다. 단순히 메모리에만 존재하며, 아직 영속성 컨텍스트에 저장되지 않은 상태입니다.
- 영속(Managed):
- 영속성 컨텍스트에 의해 관리되는 상태입니다. 엔티티 매니저를 통해 영속성 컨텍스트에 저장된 상태로, 데이터베이스와 동기화됩니다.
- 준영속(Detached):
- 영속성 컨텍스트에서 더 이상 관리하지 않는 상태입니다. 트랜잭션이 종료되거나 엔티티 매니저가 종료되면 엔티티는 준영속 상태가 됩니다.
- 삭제(Removed):
- 영속성 컨텍스트에서 제거된 상태입니다. 트랜잭션이 커밋되면 실제로 데이터베이스에서도 삭제됩니다.
영속성 컨텍스트의 주요 기능
1. 엔티티 저장:
EntityManager em = ...;
EntityTransaction tx = em.getTransaction();
tx.begin();
Member member = new Member();
member.setId("member1");
member.setName("John Doe");
em.persist(member); // 엔티티를 영속성 컨텍스트에 저장
tx.commit(); // 트랜잭션 커밋, DB에 반영
2. 엔티티 조회:
Member foundMember = em.find(Member.class, "member1");
3. 엔티티 삭제:
em.remove(foundMember);
4. 엔티티 업데이트:
foundMember.setName("Jane Doe");
영속성 컨텍스트는 JPA의 핵심 개념으로, 엔티티 객체를 관리하고 데이터베이스와의 지속성을 유지하는 중요한 역할을 합니다. 이를 통해 애플리케이션 내에서 엔티티 객체를 효율적으로 관리할 수 있으며, 데이터베이스와의 동기화를 자동화할 수 있습니다.
영속성 상태의 장점
영속성 컨텍스트의 장점으로는 1차 캐시, 동일성(identity) 보장, 트랜잭션을 지원하는 쓰기 지연, 변경 감지, 지연 로딩 등이 있습니다. 각각에 대해 자세히 설명드리겠습니다.
1차 캐시 (First Level Cache)
1차 캐시는 엔티티 매니저(Entity Manager) 내부에 존재하는 캐시입니다. 영속성 컨텍스트에 엔티티를 저장할 때, 이 엔티티는 1차 캐시에 저장됩니다. 다음과 같은 장점이 있습니다:
- 중복 조회 방지: 동일한 엔티티를 여러 번 조회해도 데이터베이스를 조회하지 않고 1차 캐시에서 반환합니다.
- 성능 향상: 데이터베이스 조회 횟수를 줄여 성능을 향상시킵니다.
동일성 보장 (Identity Guarantee)
영속성 컨텍스트는 동일한 엔티티를 조회할 때 항상 동일한 객체를 반환합니다. 다음과 같은 장점이 있습니다:
- 객체 동일성 보장: 동일한 트랜잭션 내에서는 동일한 엔티티 객체를 보장합니다. 이를 통해 객체의 동일성을 유지할 수 있습니다.
트랜잭션을 지원하는 쓰기 지연 (Transactional Write-behind)
쓰기 지연은 변경된 엔티티들을 트랜잭션 종료 시점에 한꺼번에 데이터베이스에 반영하는 기능입니다. 다음과 같은 장점이 있습니다:
- 성능 최적화: 여러 변경 작업을 모아서 한 번에 처리하므로 데이터베이스의 부하를 줄일 수 있습니다.
- 일관성 보장: 트랜잭션이 완료되기 전까지 변경 내용을 반영하지 않으므로, 데이터베이스의 일관성을 유지할 수 있습니다.
변경 감지 (Dirty Checking)
변경 감지는 영속성 컨텍스트에서 관리하는 엔티티 객체의 변경 사항을 자동으로 감지하여 트랜잭션 종료 시점에 데이터베이스에 반영하는 기능입니다. 다음과 같은 장점이 있습니다:
- 자동 업데이트: 별도의 코드 없이도 엔티티 객체의 변경 사항을 자동으로 반영합니다.
- 편리함: 개발자가 명시적으로 변경 사항을 추적할 필요가 없습니다.
지연 로딩 (Lazy Loading)
지연 로딩은 실제로 엔티티의 연관된 데이터를 사용할 때까지 데이터베이스 조회를 미루는 기능입니다. 다음과 같은 장점이 있습니다:
- 불필요한 데이터 로딩 방지: 필요할 때만 데이터를 로딩하여 성능을 최적화합니다.
- 효율성: 연관된 데이터를 사용하는 시점까지 조회를 지연시키므로 메모리 사용을 최소화합니다.
플러시 flush()
영속성 컨텍스트의 변경 내용을 데이터베이스에 반영하는 중요한 메커니즘입니다. 트랜잭션 커밋을 실행하면 변경 내용이 데이터베이스에 반영됩니다. 트랜잭션 커밋이 일어날 때 플러시도 함께 발생하여 변경 내용을 데이터베이스에 반영할 수 있습니다. 즉, 플러시는 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영하는 작업입니다.
플러시가 발생하는 시점
- 트랜잭션 커밋 시
- JPQL 쿼리 실행 시
- 명시적으로 flush() 메서드 호출 시
플러시 발생 시의 동작
- 변경 감지 (Dirty Checking): 영속성 컨텍스트에 있는 엔티티 중 변경된 엔티티를 감지합니다.
- 수정된 엔티티를 쓰기 지연 SQL 저장소에 등록: 변경된 엔티티에 대한 수정 사항을 SQL로 작성하여 쓰기 지연 SQL 저장소에 등록합니다.
- 쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송: 쓰기 지연 SQL 저장소에 등록된 쿼리를 데이터베이스에 전송하여 실제로 데이터베이스에 반영합니다. 이 과정에서 등록, 수정, 삭제 쿼리가 실행됩니다.
플러시와 트랜잭션 커밋의 관계
플러시와 트랜잭션 커밋은 밀접한 관계가 있습니다. 트랜잭션 커밋이 일어나면, JPA는 먼저 플러시를 호출하여 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영합니다. 그 후, 트랜잭션이 커밋됩니다. 이를 통해 데이터베이스의 일관성과 무결성을 보장할 수 있습니다.
@Transactional
public void exampleMethod() {
// 엔티티 변경
entity.setSomeValue("newValue");
// 명시적 플러시 호출
entityManager.flush();
// 추가 작업
}
- **플러시(flush())**는 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영하는 작업입니다.
- 플러시는 트랜잭션 커밋 시, JPQL 쿼리 실행 시, 명시적인 flush() 메서드 호출 시 발생합니다.
- 플러시가 발생하면 변경 감지, 쓰기 지연 SQL 저장소에 등록, SQL 쿼리를 데이터베이스에 전송하는 순서로 작업이 수행됩니다.
- 트랜잭션 커밋 시 플러시가 자동으로 호출되어 변경 내용이 데이터베이스에 반영됩니다.