✅ 영속성 컨텍스트란?
우리말로 간단하게 이야기하면 ‘엔티티를 영구 저장하는 환경’이라는 뜻으로 번역하고 있다. 엔티티 매니저로 엔티티를 저장하거나 조회하면 엔티티 매니저는 영속성 컨텍트에 인티티를 보관하고 처리한다.
- EntityManagerFactory(엔티티 매니저 팩토리):
- EntityManagerFactory는 EntityManager 인스턴스를 생성하고 관리하는 역할을 한다. 일반적으로 JPA 애플리케이션이 시작될 때 하나만 생성된다.
- EntityManagerFactory는 어떤 영속성 유닛(보통 persistence.xml 파일에 정의됨)을 사용할 것인지와 관련 설정을 제공하여 생성된다.
- EntityManager(엔티티 매니저):
- EntityManager는 엔티티에 대한 CRUD(Create, Read, Update, Delete) 작업을 수행하는 데 사용된다. 이는 Java 애플리케이션과 기밀 데이터베이스 간의 다리 역할을 한다.
- 각 EntityManager 인스턴스는 특정한 영속성 컨텍스트와 연관된다. 이 컨텍스트 내에서 일련의 엔티티를 관리하며, 영속성 컨텍스트는 엔티티의 짧은 수명 동안 메모리 내 캐시 역할을 한다.
- EntityManager는 새로운 엔티티를 영속화하거나 데이터베이스에서 엔티티를 검색하고, 엔티티를 업데이트하거나 삭제하는 데 필요한 메서드를 제공한다. 또한 이러한 작업에 대한 트랜잭션을 관리한다.
👉 간단하게 EntityManagerFactory는 Entity를 관리하기 위한 EntityManager을 생성하기 위한 공장이다. EntitymangerFactory는 생성 비용이 많이 들기 때문에 보통 초기에 하나만 생성되고, EntityManger을 통해서 트랜잭션을 관리하게 된다.
✅ 엔티티의 생명 주기
영속 상태란 Entity 클래스가 Context에서 Entity Manger에 의해서 관리되는 상태를 의미한다.
- 비영속(new/transient) : 영속성 컨텍스트와 전혀 관계가 없는 상태
- 엔티티 객체가 생성되었지만 아직 영속성 컨텍스트에 관리되지 않은 상태이다.
- 데이터베이스에 저장되지 않았으며, 영속성 컨텍스트에 등록되지 않았다.
- 보통
new
연산자를 사용하여 엔티티 객체를 생성한 직후에 해당 상태에 있다.
- 영속(managed) : 영속성 컨텍스트에 저장된 상태
- 엔티티가 영속성 컨텍스트에 등록되어 관리되는 상태이다.
- 데이터베이스에 저장되거나 이미 저장된 엔티티를 영속성 컨텍스트가 관리한다.
- 엔티티의 변경 사항이 자동으로 추적되며, 트랜잭션 내에서 업데이트가 가능하다.
- 준영속(Detached) : 엔티티가 영속성 컨텍스트에서 분리된 상태
- 영속성 컨텍스트를 닫거나, 영속성 컨텍스트를 초기화할 때 발생한다.
- 트랜잭션을 벗어난 후, 영속성 컨텍스트에서 더 이상 관리되지 않습니다.
- 데이터베이스와는 무관하게 독립적으로 작동하며, 변경 사항을 추적하지 않습니다.
- 일반적으로 직렬화, 웹 애플리케이션 세션 종료 등과 관련된 상태입니다.
- 삭제(Removed) : 엔티티를 영속성 컨텍스트와 데이터베이스에서 삭제
- 엔티티가 영속성 컨텍스트에서 삭제될 상태이다. 삭제 예정이지 삭제된 상태가 아니다.
- 삭제 요청을 받은 엔티티는 트랜잭션이 커밋될 때 실질적으로 데이터베이스에서 삭제된다.
- 삭제된 엔티티는 더 이상 영속성 컨텍스트에서 관리되지 않는다.
✅ 영속성 컨텍스의 특징
- Entity 객체를 관리하기 위해 @Id 어노테이션을 사용해 식별자 값으로 관리한다
- flush()
영속성 컨텍스트의 변경 내용을 데이터베이스에 동기화하는 것이 플러시(flush)다. 플러시는 영속성 컨텍스트에 보관된 엔터티를 지우는 것이 아니다.
- 1차 캐시
1차 캐시의 키는 식별자 값이다. 그리고 식별자 값은 데이터베이스 기본 키와 매핑되어 있다. 따라서 영속성 컨텍스트에 데이터를 저장하고 조회하는 모든 기준은 데이터베이스의 기본 키 값이다.
em.find()
를 호출하면 우선 1차 캐시에서 식별자 값으로 엔티티를 찾는다. 엔티티가 있으면 데이터베이스를 조회하지 않고 메모리에 있는 1차 캐시에서 엔티티를 조회해서 반환한다.만약 엔티티가 없을 경우 데이터 베이스에서 식별자 값에 매핑되는 기본 키 값으로 조회하고, 반환된 row를 엔티티 객체로 매핑하고 1차 캐시에 저장한 후에 엔티티를 반환한다.
이를 통해 엔티티를 찾을 때 성능상 이점과 동일성을 보장 받을 수 있다.
- 쓰기 지연 (transactional write-behind)
영속성 컨텍스트에 엔티티를 저장한다고 해서 데이터베이스에 바로 저장되지 않는다. 쓰기 지연 SQL 저장소와 1차 캐시를 사용하여 SQL과 @Id, Entity 객체를 저장해둔다. 트랜잭션이 커밋(commit)하는 순간 flush() 메소드를 호출하여 데이터베이스에 저장한다.
엔티티 매니저는 트랜잭션을 커밋하기 직전까지 데이터베이스에 엔티티를 저장하지 않고 내부 쿼리 저장소에 INSERT SQL을 차곡차곡 모아둔다. 그리고 트랜잭션을 커밋할 때 모아둔 쿼리를 데이터베이스에 보내는데 이것을 트랜잭션을 지원하는 쓰기 지연이라 한다.
Uploaded by N2T