ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 영속성 컨텍스트의 기능
    spring/스프링 입문 주차 2024. 1. 25. 09:39

    영속성 컨텍스트는 Entity 객체를 효율적으로 쉽게 관리하기 위해 만들어진 공간이다.
    - 영속성 컨텍스트가 어떻게 Entity 객체를 효율적으로 관리하고 있는지 살펴보자

    영속성 컨텍스트는 내부적으로 캐시 저장소를 가지고 있다.
    - 우리가 저장하는 Entity 객체들이 1차 캐시 즉, 캐시 저장소에 저장된다고 생각하면 된다.
    - 캐시 저장소는 Map 자료구조 형태로 되어있다.
     - key에는 @Id로 매핑한 기본 키 즉, 식별자 값을 저장한다.
     - value에는 해당 Entity 클래스의 객체를 저장한다.
     - 영속성 컨텍스트는 캐시 저장소 Key에 저장한 식별자 값을 사용하여 Entity 객체를 구분하고 관리한다.

    영속성 컨텍스트가 이 캐시 저장소를 어떻게 활용하고 있는지 살펴보자.
    - em.persist() 메서드가 호출되면 Entity 객체를 캐시 저장소에 저장한다.
    - em > persistenceContext > entitiesBykey를 확인해 보면 key-value 형태로 정보가 저장되어있음을
     확인할 수 있다.

    Entity 조회
    1. 캐시 저장소에 조회하는 Id가 존재하지 않는 경우
     a 캐시 저장소 조회
     b DB SELECT 조회 후 캐시 저장소에 저장
    - em.find(Memo.class, 1) 호출 시 캐시 저장소를 확인 한 후 해당 값이 없다면,
     DB에 SELECT 조회 후 해당 값을 캐시 저장소에 저장하고 반환한다.
     
    2. 캐시 저장소에 조회하는 Id가 존재하는 경우
    - em.find(Memo.class, 1) 호출 시 캐시 저장소에 식별자 값이 1이면서 Memo Entity 타입인 값이 있는지 조회
     - 값이 있다면 Entity 객체를 반환한다.

    1차 캐시 사용의 장점
    1. DB 조회 횟수를 줄임
    2. '1차 캐시'를 사용해 DB row 1개 당 객체 1개가 사용되는 것을 보장(객체 동일성 보장)

    Entity 삭제
    1. 삭제할 Entity를 조회한 후 캐시 저장소에 없다면 DB에 조회해서 저장한다.
    2. em.remove(entity);
    - em.remove(memo) 호출 시 삭제할 때 Entity를 DELETE 상태로 만든 후 트랜잭션 commit 후
     Delete SQL이 DB에 요청된다.


    쓰기 지연 저장소(ActionQueue)

    JPA의 트랜잭션 학습하면서 JPA가 트랜잭션 처럼 SQL을 모아서 한번에 DB에 반영한다는 것을 배웠다.
     - JPA는 이를 구현하기 위해 쓰기 지연 저장소를 만들어 SQL을 모아두고 있다가 트랜잭션
      commit 후 한번에 DB에 반영한다.
     - Debugging을 통해 실제로 쓰기 지연 저장소에 SQL을 모아서 한번에 반영하는지 확인해보자.
     - 실제로 기록을 확인해보면 트랜잭션 commit 호출 전까지는 SQL 요청이 없다가 트랜잭션 commit 후
      한번에 Insert SQL 2개가 순서대로 요청된 것을 확인할 수 있다.

    flush()
    - 트랜잭션 commit 후 쓰기 지연 저장소의 SQL들이 한번에 요청됨을 확인했다.
    - 사실 트랜잭션 commit 후 추가적인 동작이 있는데 바로 em.flush(); 메서드의 호출이다.
    - flush 메서드는 영속성 컨텍스트의 변경 내용들을 DB에 반영하는 역할을 수행한다.
     - 즉, 쓰기 지연 저장소의 SQL들을 DB에 요청하는 역할을 수행한다.

    - em.flush(); 메서드가 호출되자 바로 DB에 쓰기 지연 저장소의 SQL이 요청되었다.
    - 이미 쓰기 지연 저장소의 SQL이 요청 되었기 때문에 더 이상 요철청할 SQL이 없어 트랜잭션이
     commit 된 후에 SQL 기록이 보이지 않는다.

    - 추가) 트랜잭션을 설정하지 않고 flush 메서드를 호출하면 no transaction is in progress 메시지와 함께 
     TransactionRequiredException 오류가 발생합니다.
     - Insert, Update, Delete 즉, 데이터 변경 SQL을 DB에 요청 및 반영하기 위해서는 트랜잭션이 필요하다.
      (Select 는 상관 없음)

    commit 메서드엔 flush 기능이 포함되어 있다는 걸 알 수 있다.


    변경 감지(Dirty Checking)
    - 영속성 컨텍스트에 저장된 Entity가 변경될 때 마다 Update SQL이 쓰기 지연 저장소에 저장된다면?
     - 하나의 Update SQL로 처리할 수 있는 상황을 여러번 Update SQL을 요청하게 되기 때문에 비효율적이다.
    - 그렇다면 JPA는 어떻게 Update를 처리할까?
     - em.update(entity) 같은 메서드를 지원할 것 같지만 찾아볼 수 없다.

    - JPA에서는 Update를 어떻게 처리하는지 살펴보자.
    - JPA는 영속성 컨텍스트에 Entity를 저장할 때 최초 상태(LoadedState)를 저장한다.
     - 트랜잭션이 commit되고 em.flush(); 가 호출되면 Entity의 현재 상태와 저장한 최초 상태를 비교한다.
     - 변경 내용이 있다면 Update SQL을 생성하여 쓰기 지연 저장소에 저장하고 모든 쓰기 지연 저장소의
      SQL을 DB에 요청한다.
     - 마지막으로 DB의 트랜잭션이 commit 되면서 반영된다.
    - 따라서 변경하고 싶은 데이터가 있다면 먼저 데이터를 조회하고 해당 Entity 객체의 데이터를 변경하면
     자동으로 Update SQL이 생성되고 DB에 반영된다.
     - 이러한 과정을 변경 감지, Dirty Checking이라 부른다.

    변경 감지 또한 마찬가지로 트랜잭션이 걸려 있어야 한다.

    'spring > 스프링 입문 주차' 카테고리의 다른 글

    SpringBoot의 JPA  (1) 2024.01.25
    엔티티의 상태  (1) 2024.01.25
    JPA란 무엇일까  (0) 2024.01.23
    제어의 역전, ApplicationContext  (2) 2024.01.22
    IoC Container 와 Bean  (0) 2024.01.22
Designed by Tistory.