영속성 컨텍스트 (Persistence Context)란?
Entity를 영구적으로 저장하는 환경으로, JPA를 이해하기 위해 빼놓을 수 없는 개념이다.
논리적인 개념이기에 눈에 보이지 않고, EntityManager를 통해 접근할 수 있다.
우리가 이전 시간에 사용했던 EntityManager.persist(Entity)가 Entity를 영속성 컨텍스트에 저장한다는 뜻이다.
영속성 컨텍스트의 생명주기
영속성 컨텍스트엔 아래의 4가지 생명주기가 있다.
비영속 (New)
이제 막 생성되어 영속성 컨텍스트와 아무런 상관이 없는 상태이다.
Member member = new Member();
member.setId("member");
member.setName("회원");
영속 (Managed)
엔티티가 영속성 컨텍스트에 의해 관리받는 상태이다.
EntityManager em = emf.createEntityManager();
em.getTransaction.begin();
em.persist(member);
영속되었다고 바로 DB에 바로 반영되는게 아니라, commit을 해야 반영된다.
아래와 같이 로그를 띄워보면, persist하는 시점에 INSERT 쿼리가 전송되는게 아니라 commit할 때 전송되는것을 확인할 수 있다.
Member member1 = new Member();
member1.setUsername("member1");
member1.setAge(10);
System.out.println("========= BEFORE PERSIST ========");
em.persist(member1);
System.out.println("========= AFTER PERSIST ========");
System.out.println("========= BEFORE COMMIT ========");
tx.commit();
System.out.println("========= AFTER COMMIT ========");
준영속 (Detached)
영속되어있던 엔티티를 영속성 컨텍스트에서 다시 분리시킨 상태이다.
영속성 컨텍스트에서 더 이상 관리하지 않기 때문에 수정하거나 삭제해도 DB에 반영되지 않는다.
em.persist(member);
em.detach(member);
삭제 (Removed)
엔티티를 DB에서 제거한다.
Detached는 "엔티티를 관리하지 않겠다"라는 뜻이고, Removed는 "엔티티를 DB에서 삭제하겠다"라는 뜻이다.
Detached는 생성되건 수정되건 삭제되건 간에 쿼리가 아예 나가지 않고, Removed는 DELETE 쿼리가 나간다.
영속성 컨텍스트의 특징
1차 캐시
영속성 컨텍스트엔 캐시가 내장되어있다.
이 캐시는 DB와 사용자 사이에서 엔티티를 저장해주는 역할을 하는데,
이런 특징으로 인해 엔티티를 검색할 때 DB에 SELECT 쿼리를 계속 날리는게 아니라 우선 캐시에 엔티티가 있는지 확인한 후, 없을때만 SELECT 쿼리를 날리고 만약 있다면 캐시에서 엔티티를 바로 반환한다.
이전에 em.persist를 호출했을 때 바로 INSERT 쿼리가 실행되지 않은 이유도 엔티티를 DB에 바로 저장하지 않고 1차 캐시에 우선 저장하기 떄문이다.
동일성 보장
엔티티를 캐시에서 조회하기 때문에, 같은 엔티리를 조회하면 완전히 같은 객체가 반환된다.
Member a = em.find(Member.class, member.getId());
Member b = em.find(Member.class, member.getId());
System.out.println("a == b = " + (a == b)); //true
쓰기 지연
이전의 예제를 통해 Persist를 호출하면 DB가 아닌 1차 캐시에 우선 저장된다는 것을 알 수 있었다.
그런데 이 1차 캐시에 저장된 엔티티를 어떻게 DB에 반영할까?
영속성 컨텍스트에는 1차 캐시 외에도 "쓰기 지연 SQL 저장소" 가 존재한다.
우리가 엔티티를 등록, 수정, 삭제할 때마다 1차 캐시에 반영되는 동시에 쓰기 지연 SQL 저장소에 실행해야될 SQL들이 쌓이는 것이다.
아래와 같이 영속성 컨텍스트가 변경될 때마다 SQL이 쌓이고,
commit하거나 flush를 강제 호출할 때 쌓여있던 SQL들이 한번에 DB로 전송된다.
변경 감지 (Dirty Checking)
1차 캐시에는 "스냅샷" 이라는 별도의 공간이 있는데, SELECT 쿼리 수행 시 결과를 스냅샷에 저장하고, flush 할 때 Entity와 비교하기 위한 용도로 사용된다.
영속성 컨텍스트를 flush하는 시점에 엔티티와 스냅샷을 비교하고, 스냅샷과 다른 부분에 대해 자동으로 UPDATE 쿼리를 실행한다.
지연 로딩 (Lazy Loading)
OneToMany나 ManyToMany, OneToOne 등 다른 엔티티의 매핑이 되어있는 경우 관련있는 엔티티들을 SELECT시 한번에 Join 해서 다 가져오지 않고 프록시로 반환한 후, 매핑된 엔티티를 사용해야 할 때 다시 조회해서 가져온다.
출처
'Study > JPA' 카테고리의 다른 글
[JPA] 상속관계 매핑 (0) | 2022.08.26 |
---|---|
[JPA] 연관관계 매핑 (0) | 2022.08.25 |
[JPA] Entity 필드, 컬럼 매핑 (0) | 2022.03.05 |
[JPA] DB에 데이터 넣어보기 (0) | 2022.02.26 |
[JPA] JPA 프로젝트 설정 (0) | 2022.02.26 |