JPA : 영속성 컨텍스트와 엔티티의 동일성

    이 게시글은 자바 ORM 표준 JPA 프로그래밍 책을 보고 공부한 내용을 정리한 글입니다.

     


    영속성 컨텍스트와 1차 캐시

    영속성 컨텍스트는 내부적으로 1차 캐시를 가지고 있다. 이 1차 캐시는 DB에서 가져온 엔티티를 영속화 해두는 저장소 역할을 한다. 이 저장소는 스냅샷을 만들어 더티 체킹도 하지만, PK 값으로 엔티티를 관리하기 때문에 엔티티의 비교에도 아주 유용한 기능을 제공한다.

     

     


    영속성 컨텍스트가 1개 일 때, 엔티티 비교.

    영속성 컨텍스트가 1개일 때 엔티티를 비교하면 어떻게 될까? OSIV 환경을 가정하고 비교해보자. 먼저 빈 영속성 컨텍스트에 PK가 1인 엔티티를 DB에서 영속화했다. 그럼 영속성 컨텍스트의 1차 캐시에 이 엔티티는 영속화된다. 그리고 이 엔티티를 A라는 변수에 참조하도록 한다. 

    다시 한번 PK가 1인 엔티티를 조회해서 B에 저장하는 상황을 가정하자. JPA는 DB에 조회 쿼리를 날리기 전에 영속성 컨텍스트의 1차 캐시를 살펴본다. 이 때, 1차 캐시에 영속화된 엔티티가 존재하기 때문에 이 엔티티가 B에 참조하도록 된다. 

    위와 같은 상황이면 A와 B는 동일한 참조값을 가진다. 영속성 컨텍스트의 1차 캐시에 영속화 된 동일한 엔티티를 가리키기 때문이다. 따라서 영속성 컨텍스트가 1개 일 때, 동일한 엔티티를 비교하면 아래 내용을 만족한다.

    1.  A == B 
      • 같은 주소를 가지기 때문에 A == B를 만족한다.
    2. A.equlas(B) 
      • 같은 주소를 가지기 때문에 2항도 만족한다.
    3. @Id
      • 같은 엔티티기 때문에 DB에서도 동일성이 보장된다.

     

     


    영속성 컨텍스트가 2개 일 때, 엔티티 비교.

    영속성 컨텍스트가 1개 일 때, 동일한 엔티티는 세 항목을 만족했다. 영속성 컨텍스트가 2개인 경우에는 어떻게 바뀔까? 영속성 컨텍스트가 2개인 경우 트랜잭션마다 영속성 컨텍스트 생성 전략을 살펴보면 된다. 먼저 아래와 같이 동작했다고 해보자.

     

    1. 트랜잭션 1이 시작해서 PK = 1 인 엔티티를 조회해서 영속화하고, 그 엔티티를 A에 참조하도록 했다.
    2. 트랜잭션 1가 종료하며 영속성 컨텍스트가 종료되고, 엔티티는 준영속화된다.
    3. 트랜잭션 2가 시작해서 PK = 1 인 엔티티를 조회해서 영속화하고, 그 엔티티를 B에 참조하도록 했다.
    4. 트랜잭션 2가 종료하며 영속성 컨텍스트가 종료되고, 엔티티는 준영속화된다. 

    위 경우에 A와 B는 서로 다른 객체를 참조한다. 왜냐하면 2의 과정에서 영속성 컨텍스트가 종료되었기 때문에 3을 할 때, 영속성 컨텍스트의 1차 캐시를 살펴보는 것이 아니라 다시 한번 DB에서 엔티티를 불러와서 다른 영속성 컨텍스트에 저장하기 때문이다. 따라서 A와 B는 같은 엔티티를 조회했지만, 서로 다른 객체를 가리키게 된다. 

    1.  A != B 
      • 서로 다른 객체를 가리키기 때문에  == 비교는 실패한다.
    2. A.equlas(B) 
      • 같은 엔티티를 가리키기 때문에 equals는 성공한다. 대신 이 때, 어떤 컬럼이 equals의 기준이 될 지 미리 결정해야한다.
    3. @Id
      • 같은 엔티티기 때문에 DB에서도 동일성이 보장된다.

     

     


    정리

    • 영속성 컨텍스트가 1개 일 때, 같은 엔티티를 비교하게 되면  ==, equals, @Id 모두 동일성을 보장한다.
    • 영속성 컨텍스트가 2개 이상일 때, 같은 엔티티를 비교하게 되면 == 비교는 실패한다. equals와 @Id는 동일성을 보장하지만, equals는 개발자가 직접 구현해야한다. 

    댓글

    Designed by JB FACTORY