Web/JAVA

[JPA] 영속성 컨텍스트

부에나온다 2024. 3. 20. 16:21

1. 영속성 컨텍스트

  • ORM은 객체와 데이터베이스 테이블의 맵핑을 통해 엔티티 클래스 객체안에 포함된 정보를 테이블에 저장하는 기술
  • JPA에서는 엔티티 객체 정보를 영속성 컨텍스트를 통해 어플리케이션 내에서 오래 지속되도록 보관한다.
  • Server side와 Database 사이에 엔티티를 저장하는 논리적인 영역이라고 할 수 있다. 엔티티 매니저로 엔티티를 저장하거나 조회하면 엔티티 매니저는 영속성 컨텍스트에 엔티티를 보관하고 관리한다.
  • 영속성 컨텍스트는 엔티티 매니저(Session)를 생성할 때 하나 만들어진다. 그리고 엔티티 매니저(Session)을 통해서 영속성 컨텍스트에 접근할 수 있고 영속성 컨텍스트를 관리할 수 있다.
  • EntityManagerFactory : EntityManager를 생성한다. 불변객체로 Thread-Safe 하다. 싱글톤패턴으로 재활용이 가능하다.
  • EntityManager : 영속성 컨텍스트(가상 데이터베이스)를 관리하는 객체

2. 엔티티의 생명주기

  • 비영속 : 엔티티 객체를 생성했다. 현재 순수한 상태로 아직 저장하지 않은 단계. 
// 객체를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
  • 영속 : 엔티티 매니저를 통해서 엔티티를 영속성 컨텍스트에 저장(persist())했다. 이렇게 영속성 컨텍스트가 관리하는 엔티티를 영속상태라고 부른다.
Member member = new Member();
member.setId("member1");
member.setUsername("홍길동");

// 객체를 영속성 컨텍스트에 저장(영속)
em.persist(member);
  • 준영속 : 영속성 컨텍스트가 관리하던 영속 상태의 엔티티를 영속성 컨텍스트가 관리하지 않으면 준영속 상태 detach() 하면 관련이 없어진다.
em.detach(member); // 엔티티를 영속성 컨텍스트에서 분리

em.claer(); // 영속성 콘텍스트를 비움

em.close(); // 영속성 콘텍스트를 종료
  • 삭제 : 엔티티를 영속성 컨텍스트와 데이터베이스에서 삭제한다.
// 객체를 삭제한 상태(삭제)
em.remove(member);

 

3. 영속성 컨텍스트의 장점

       1차 캐시

  • 영속 상태의 Entity는 모두 영속성 컨텍스트에 HashMap(key(@Id) = value(Entity)) 로 저장된다.
  • 따라서 식별자 (@Id)가 반드시 있어야 한다.
Member member = new Member();
member.setId("member1"); // 직접 id 값을 초기화 암으로써 준영속상태로 인지한다.
member.seUsername("회원1");
// 엔티티 영속(1차 캐시 저장)
em.persist(member);

// 1차 캐시에서 조회
em.find(Member.class, "member1");
  • 아직 flush가 일어나지 않아 1차 캐시에 저장된다. 추후 flush를 통해 db 저장된다.
  • 만약에 1차 캐시에 없으면 db 조회 후 1차 캐시에 저장한 후 반환한다.
    • 보통 entityManager는 transaction 단위로 만들고 종료되므로 em 종료시 캐시도 날라간다.
    • 순간적인 성능 이점보다는 비즈니스 로직이 굉장히 복잡할때 좋다.

       동일성 보장

  • 1차 캐시가 있기 때문에 영속 엔티티의 동일성(메모리 주소가 같음을 의미)을 보장해 준다.
  • 1차 캐시로 반복 가능한 읽기 등급의 트랜잭션 격리 수준을 db가 아닌 어플리케이션 차원에서 제공한다.

       트랜잭션으로 인한 쓰기 지연

  • 쓰기 지연 SQL 저장소가 존재한다.
  • entity 분석 후 insert 쿼리를 생성하고 쓰기 지연 SQL 저장소에 쌓는다.
  • commit 하는 순간 쿼리들이 flush 되면서 db로 날아간다.
  • 즉, 트랜잭션이 끝나야 Commit이 이루어지고 반영된다.

       변경 감지(dirty checking)

  • em.update 와 같은 코드를 작성하지 않는다.
  • flush 발생 시 entity와 스냅샵을 비교한다. 스냅샷을 처음 db에서 읽어왔을때 내용이다.
  • 바뀐내용이 있으면 쓰기 지연 SQL 저장소에서 update 쿼리를 작성하여 commit 시 db에 적용한다.