JPA 영속성 컨텍스트

pastaCoder·2022년 11월 3일
0

Entity Manager(영속성 컨텍스트)

엔티티 매니저는 엔티티를 저장, 수정, 삭제, 조회등 엔티티와 관련된 모든 일을 처리한다. 이름 그대로 엔티티를 관리하는 관리자임.
개발자 입장에서 엔티티 매니저는 엔티티를 저장하는 가상의 데이터베이스로 생각하면 됨.

엔티티 매니저는 엔티티 매니저 팩토리를 통해 만듬.
엔티티 매니저 팩토리는 여러 스레드가 동시에 접근해도 안전하지만, 에닡티 매니저는 여러 스레드가 동시에 접근하면 동시성 문제가 발생하므로 스레드간에 절대 공유하면 안됨.

엔티티의 생명주기

  • 비영속 : 영속성 컨텍스트와 전혀 관계가 없는 상태
  • 영속 : 영속성 컨텍스트에 저장된 상태
  • 준영속 : 영속성 컨텍스트에 저장되었다가 분리된 상태
  • 삭제 : 삭제된 상태

비영속이 조금 헷갈릴 수 있는데, 아래 예시처럼 영속성 컨텍스트나 데이터베이스와는 전혀 관련이 없는 순수한 객체상태를 비영속 상태라 한다.

Member member = new Member();
member.setId("member1");
member.setUsername("회원1");

1차캐시

Member member = new Member();
member.setId("member1");
member.setUsername("회원1");

em.persist(member);

위 코드를 실행하면 회원 엔티티를 1차 캐시에 저장한ㄷ. 회원 엔티티는 아직 데이터베이스에 저장되지 않음

식별자값은 데이터베이스 기본키와 매핑되어있음.]

이 상태에서

public<T> T find(Class<T> entityClass, Object primaryKey);

위처럼 정의된 find 메소드로 em.find()를 호출하면 먼저 1차캐시에서 엔티티를 찾고 만약 찾는 엔티티가 1차캐시에 없으면 데이터베이스에서 조회함

  • 1차 캐시는 서로 공유하지 않고 하나의 쓰레드가 시작할때부터 끝날때까지 잠깐 사용하는 글로벌하지 않는 캐시이다.
  • 100명 한테 요청 100개 오면, 엔티티 매니저 100개 생기고 1차캐시도 100개 생긴다. 스레드 종료되면, 그때 다 사라진다.
  • 트랜잭션의 범위 안에서만 사용하는 굉장히 짧은 캐시 레이어이다.
  • 전체에서 쓰는 글로벌 캐시는 2차 캐시라고 한다.

영속 엔티티의 동일성 보장

Member a = em.find(Member.class, "member1");
Member b = em.find(Member.class, "member2");

위에서 a==b는 참이다. 조회를 할 때 1차캐시에 있는 같은 인스턴스를 반환하기때문에 둘은 같다. 따라서 영속성 컨텍스트는 성능상 이점(캐시를 활용)과 엔티티의 동일성을 보장함

변경 감지

JPA 엔티티 수정방식은

member.setUsername("testuser");
// em.update(member);

위처럼 엔티티매니저에 update를 해야할 것 같지만, 엔티티의 데이터만 변경해줘도 데이터베이스에 반영이된다.
JPA는 엔티티를 영속성 컨텍스트에 보관할 때, 최초상태를 복사해서 저장해둔다. 이것을 스냅샷이라함.
그리고 플러시 시점에 스냅샷과 엔티티를 비교해서 변경된 엔티티를 찾음.
이후 쓰기지연 저장소에 변경 SQL을 보내고 커밋할때 변경사항을 적용한다.
변경감지는 영속성 컨텍스트가 관리하는 영속상태의 엔티티에만 적용된다.

병합

준영속, 비영속 상태의 엔티티는 엔티티매니저가 더이상 관리를 하지 않아 영속성 컨텍스트가 제공하는 1차캐시, 동일성 보장, 트랜잭션을 지원하는 쓰기지연, 변경 감지, 지연 로딩 같은 기능들을 사용할 수 없다.
준영속 상태의 엔티티를 다시 영속상태로 변경할때 병합을 씀
merge() 메소드는 준영속 상태의 엔티티를 받아서 그 정보로 새로운 영속상태의 엔티티를 반환한다.

Member mergeMember = em.merge(member/*준영속, 비영속 상태의 엔티티*/);

0개의 댓글