본문 바로가기
JAVA

[JPA] JPA와 영속성 컨텍스트(Persistent Context)

by 고 민 2023. 12. 29.
728x90
반응형

영속성(Persistent)이란 ?

영속성이란 어플리케이션이 종료되어도 사라지지 않는 데이터의 특성이다. 

영속성을갖이 않는 데이터는 메모리에 존재했다가 어플리케이션이 종료되는 순간 사라진다. 

우리는 데이터를 지속적으로 보관하기 위해 데이터베이스에 영구 저장함으로서 영속성을 부여한다. 

영속성 컨텍스트(Persistent Conext)란? 

영속성 컨텍스트란 데이터를 영구 저장하는 환경(context)으로 해석 할 수 있다. 

영속성 컨텍스트는 EntityManager가 생성될 때 함께 생성된다. 

어플리케이션과 DB사이에 객체를 보관하는 가상의 공간이라고 생각하면 이해하기 편하다. 

단, JPA의 영속성 컨텍스트는 엔티티매니저가 생성한 트랜잭션 내에서만 유효하다.

트랜잭션이 종료되면 영속성 선텍스트에 저장된 데이터도 사라진다. 

영속성 컨텍스는 논리적인 개념이다. 즉, 실체가 보이지 않는다. 

Entity 생명주기 

비영속(new/transident)

영속이 제거되거나 영속성 컨텍스트와 전혀 관계 없는 새로운 상태.

영속(managed)

영속성 컨텍스트에 관리된 상태 .

영속 상태에서는 DB에 저장되지 않는다.

준영속(detached)

영속성 컨텍스트의 관리에서 분리된 상태.

이 상태에선 영속성 컨텍스트의 모든 기능을 이용할 수 없다. 

삭제(removed)

영속성 컨텍스트가 제거된상태.

JPA의 영속성 관리

EntityManager.persist(Entity) - 엔티티를 영속성 컨텍스에서 관리한다. 

(*엔티티 = JPA가 관리하는 객체)

Member member = new Member();
 
// 파라미터로 넘긴 객체를 영속성 컨텍스트가 관리한다. (= 영속상태가 된다)
EntityManager.persist(member);

영속성 컨텍스트의 이점 

1차 캐시

영속성 컨텍스트 내부 Key, Value로 된 Map 형태의 공간이다. 

영속성 컨텍스에서 관리하거나 조회되는 엔티티는 1차 캐시에 저장된다.

1차 캐시는 트랜잭션이 완료되면 날아가기 때문에 하나의 트랜잭션 안에서만 효과가 있다.

 

1차 캐시 흐름

1. persist() 메서드로  영속성 관리 대상이 된 엔티티는 영속성 컨텍스트의 1차 캐시에 저장된다. 

2. 조회 시 1차 캐시에서 ID를 조회해 엔티티를 찾는다. 

3-1. 엔티티가 있는 경우 1차 캐시에 있는 데이터를 가져온다. 

3-2. 엔티티가 없는 경우 DB에 접근해 데이터를 조회하고, 조회된 데이터를 엔티티로 생성해 1차 캐시에 저장한다. 

4. 조회한 엔티티를 반환한다.

영속 엔티티의 동일성 보장

JPA는 1차 캐시로 반복 가능한 읽기 등급(Repeatabel reader Level ) 의 트랜잭션 격리 수준을 데이터베이스가 아닌 애플리케이션 차원에서 제공한다. 

데이터베이스에 삽입한 엔티티와, 이 엔티티를 데이터베이스에서 조회해서 가져왔을 때 반환되는 객체의 동일성이 보장된다는 의미이다. 이것이 가능한 이유는 앞서 다뤘던 1차 캐시 때문이다. 

영속성 컨텍스트에서 관리하는 엔티티는 조회 시 우선 적으로 1차 캐시에 접근하여 엔티티가 있는지 확인하고 1차 캐시에 저장된 엔티티 인스턴스를 가져온다. 1차 캐시에서 저장된 인스턴스를 가져오기 때문에 값 뿐만 아니라 인스턴스 자체가 동일하다.

 

아래는 동일성 보장을 테스트한 예제 코드이다.

Member member = new Member(10L,"KIM"); 
EntityManager.persist(member); 

// find() - db에 접근하기 전 1차 캐시에 저장된 엔티티가 있는지 확인 후 가져온다. 
Member member2 = EntityManager.find(Member.class, 10L); 

System.out.println("result = " + member == member2);

// 출력 결과 : result = true

 

트랜잭션을 지원하는 쓰기 지연(transactional write-behind)

쓰기 지연 흐름 

1. JPA가 엔티티를 분석해 쿼리를 생성하고 쓰기 지연 SQL 저장소에 저장한다. 

2. Commit시 쓰기 지연 sql 저장소에 있는 SQL을 한꺼번에 DB에 flush 해서 반영한다. 

버퍼링 모아서 DB에 한번에 쓰기 때문에 성능적으로 이점을 얻을 수 있다. 

변경 감지

객체의 필드 값을 변경할 경우 변경을 감지하여 DB에 UPDATE SQL을 생성해 날린다. 

변경을 감지하는 원리는 다음과 같다. 

1. find 또는 persist 될때 영속성 컨텍스트에 객체의 스냅숏을 생성한다. 

2. JPA는 Commit에서 flush가 발생하면 영속성컨텍스트의 객체와 객체의 스냅숏을 비교하여 필드 값이 변경되었는지 확인하고, 변경되다면 SQL문을 생성해 쓰기 지연 SQL 저장소에 저장한다. 

3. 쓰기 지연 SQL 저장소에 저장한 SQL을 DB에 플러시한다. 

4. DB에 플러시한 SQL을 COMMIT 한다. 

5. 결과를 반환한다. 

 

지연 로딩

 

 

 

JPA는 내부적으로 1차 캐시라는 저장 공간에 데이터를 저장한다. 

예를 들어 JPA에서 엔티티 매니저에서 persist() 메서드를 사용하면, 데이터를 저장하는데, 이때 1차 캐시에도 데이터를 저장한 후 find()를 통해 자장한 데이터를 조회할 때 DB에서 조회하지 않고 1차 캐시에서 데이터를 조회해서 가져온다. 

 

 

단, 영속성 컨텍스트는 하나의 트랜잭션에서만 유효하기 때문에 트랜잭션이 종료되면 삭제된다.

 

728x90
반응형