영속성 컨텍스트(Persistence Context)
영속성 컨텍스트(Persistence Context)란 엔티티를 영구 저장하는 환경이라는 뜻으로,
애플리케이션과 데이터베이스 사이에서 객체를 보관하는 가상의 데이터베이스 같은 역할을 한다.
이 과정에서 가상의 데이터베이스에 저장할 때 EntityManager를 사용하는데 개념은 아래에서 다루겠다.
영속성 컨텍스트는 JPA를 이해하는데 가장 중요한 용어이다.
간단하게 정리하면 다음과 같다.
- 영속성 컨텍스트는 논리적인 개념
- 눈에 보이지 않음
- 엔티티 매니저를 통해 영속성 컨텍스트에 접근
즉, EntityManager로 Entity를 저장하거나 조회하면
EntityManager는 영속성 컨텍스트에 Entity를 보관하고 관리한다.
EntityManageFactory emf = Persistence.createEntityManagerFactory("persistence-name");
EntityManage em = emf.createEntityManager();
em.persist(member);
위에 코드를 보면 persist() 메서드는 단순히 Member Entity를 저장한 것 같지만
정확히 말하면 EntityManager를 사용해서 Member Entity를 영속성 컨텍스트에 저장한 것이다.
그렇다면 지금까지 설명할 때 자주 등장하는 EntityManager의 역할에 대해 알아보자.
EntityManager
EntityManager란 Entity를 저장하는 메모리상의 데이터베이스라고 볼 수 있다.
Entity를 저장하고, 수정하고, 삭제하고, 조회하는 등 Entity와 관련된 모든 일을 한다.
하지만 EntityManagerFactory와 달리 Thread-Safe하지 않기 때문에
동시성 문제가 발생할 수 있다.
그래서 EntityManager는 스레드간에 공유를 절대로 해서는 안된다.
일반적으로 EntityManager를 @PersistenceContext로 Spring이 관리해주는 방식으로 사용한다.
@PersistenceContext를 사용해서 EntityManager를 주입받으면
Spring에서 EntityManager를 Proxy로 감싼 EntityManager를 생성해서
주입해주기에 Thread-Safe를 보장한다.
@PersistenceContext
private EntityManager entityManager;
Entity의 생명주기
Entity에는 4가지 상태가 존재한다.
- 비영속(new/transient) : 영속성 컨텍스트와 전혀 관계가 없는 상태
//객체를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
- 영속(managed) : 영속성 컨텍스트에 저장된 상태
//객체를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
//객체를 저장한 상태(영속)
em.persist(member);
- 준영속(detached) : 영속성 컨텍스트에 저장되었다가 분리된 상태
//회원 엔티티를 영속성 컨텍스트에서 분리, 준영속 상태
em.detach(member);
//영속성 컨텍스트를 완전히 초기화
em.clear();
//영속성 컨텍스트를 종료
em.close();
- 삭제(removed) : 삭제된 상태
//객체를 삭제한 상태(삭제)
em.remove(member);
영속성 컨텍스트의 특징
- 영속성 컨텍스트와 식별자 값
- 영속성 컨텍스트는 Entity를 식별자 값(@Id)으로 구분한다.
- 따라서 영속 상태는 식별자 값이 반드시 있어야 한다.
- 영속성 컨텍스트에 데이터를 저장하고 조회하는 모든 기준은 기본 키 값이다.
- 트랜잭션을 지원하는 쓰기 지연
- Entity 값을 변경하면 DB에 바로 업데이트를 하지 않는다.
- 트랜잭션 내부에서 영속 상태의 Entity의 값을 변경하면 Insert Query들은 DB에 바로 보내지 않고 Query 저장소에 쿼리문들을 생성해서 쌓아둔다.
- 플러시(Flush) : 플러시는 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영하는 것을 말한다.
- 이후 EntityManager의 Flush나 트랜잭션의 commit을 통해 보내지게 된다.
- 1차 캐시에 저장 및 조회
- 영속성 컨텍스트는 내부에 Entity를 저장하는 캐시를 가지고 있는데 이것을 1차 캐시라고 한다.
- 영속 상태의 Entity는 데이터베이스에 저장되기 전(트랜잭션 호출 전)까지 모두 이곳에 저장된다.
- Entity 조회 시 1차 캐시에서 먼저 찾고 만약 존재하지 않으면 데이터베이스를 조회한다.
- 이러한 기능으로 성능상에 이점을 누릴 수 있다.
- 동일성 보장
- Entity가 1차 캐시에 저장되어 있기 때문에, 같은 식별자(@Id)에 대한 Entity는 매번 같은 인스턴스에 접근할 수 있다.
동일성 비교 : 실제 인스턴스가 같고, ==을 사용해 비교한다.
동등성 비교 : 실제 인스턴스는 다를 수 있지만 인스턴스가 가지고 있는 값이 같다. equals() 메서드로 비교한다.
- 변경 감지(Dirty Checking)
- Flush 시점에서 Entity와 스냅샷을 비교해 변경된 Entity가 있다면 쓰기 지연 SQL 저장소에 보낸다.
- 따로 Entity 수정에 대한 메서드가 필요 없다.
- 지연 로딩(Lazy Loading)
- JPA에서는 데이터를 조회할 때 즉시 로딩(EAGER)과 지연 로딩(LAZY) 두 가지 방식이 있다.
- 로딩(EAGER) 방식은 즉시 로딩은 데이터를 조회할 때 연관된 데이터까지 한 번에 불러오는 것이고, (Join)
- 지연 로딩(LAZY) 방식은 필요한 시점에 연관된 데이터를 불러오는 것이라고 할 수 있다.(select)
마치며
오늘은 영속성 컨텍스트의 개념 정리 및 사용법에 대해 알아봤습니다.
다음 포스팅에서 뵙겠습니다.
위 포스팅 글은 김영한님의 자바 ORM 표준 JPA 프로그래밍-기본편을 참고했습니다.
'[ ORM ] > JPA' 카테고리의 다른 글
[ JPA ] 상속 관계 매핑 (59) | 2024.03.18 |
---|---|
[ JPA ] 다양한 연관관계 매핑 (57) | 2024.03.13 |
[ JPA ] 연관관계 매핑 기초 (74) | 2024.03.07 |
[ JPA ] Entity Mapping (77) | 2024.02.26 |
[ JPA ] JPA 소개 (59) | 2024.02.15 |