JPA 영속성 컨텍스트란?

이동영·2024년 3월 20일

JPA

목록 보기
8/8

영속성 컨텍스트는 엔티티 영구 보관하기 위한 공간이며 어플리케이션과 데이터베이스 사이 중간에서 동작하는 가상의 DB공간 이라고 생각하면 된다. 영속성 컨텍스트는 엔티티 메니저라는 것을 통하여 영속성 컨텍스트에 접근할 수 있으며 엔티티 메니저를 통하여 영속화 된 엔티티를 관리할 수 있다. 엔티티 메니저는 1개의 요청이 들어올 때 영속성 컨텍스트를 생성하며 생성된 영속성 컨텍스트에서 엔티티를 관리하게 된다.

영속성 컨택스트의 생명주기

영속성 컨텍스트에는 다양한 생명주기가 있다.

비영속

Member member = Member.builder()
                .id("LeeDongYoung")
                .pw("ehddud12")
                .aboutMe("안녕하세요 저는 이동영 입니다. 이번에 XX사이트를 지인을 통해 가입하게 되었습니다. 앞으로도 사이트 활동을 자주 하려고 합니다. 감사합니다.")
                .memberAuth(Auth.USER)
                .memberDt(LocalDate.now())
                .build();

객체가 생성된 상태이지만 아직 영속성 컨텍스트에 등록이 되지 않은 순수 자바 객체의 상태이다.

영속


em.persist()를 호출하여 인자값으로 엔티티를 넘겨주게 되면 엔티티 메니저는 해당 엔티티를 영속성 컨텍스트에 등록하게 된다. 혹은 em.find()로 영속성 컨텍스트에 등록된 엔티티를 조회할 수 있는데 만약 영속성 컨텍스트에 엔티티가 조회한다면 1차캐시에 존재하는 엔티티를 반환하며 그렇지 않은경우 데이터베이스로 부터 SELECT문을 날려 얻은 값을 1차캐시로 등록한 뒤 영속화 된 엔티티를 반환하게 된다.

준영속

em.detach(member);를 호출하게 되면 영속성 컨텍스트에서 관리되는 엔티티는 관리 대상에서 제외되며 find()를 호출하거나 할 수 없게 된다.

삭제

em.remove(member)로 해당 엔티티를 영속성 컨텍스트 혹은 테이터베이스에서 삭제시킬 수 있다. 더이상 해당 엔티티는 존재하지 않게 된다.

1차 캐시

영속성 컨텍스트 내부에는 1차 캐시라는 공간이 존재한다. 엔티티 매니저가 영속성 컨텍스트에 엔티티를 저장하게 되는데 정확히는 엔티티는 1차 캐시라는 공간에 Map형식의 key value의 형태로 저장이 되며 엔티티에서 @Id로 선언한 PK값이 키값으로 사용된다.

영속성 컨텍스트 내부에 존재하는 엔티티를 조회하기 위해서는 em.find()라는 메소를 호출하여 엔티티를 호출할 수 있는데 1차캐시에 엔티티가 존재한다면 존재하는 엔티티를 반환하게 되지만 1차캐시에 없을 경우 엔티티 메니저는 DB로 부터 데이터 값을 조회하여 1차캐시에 엔티티를 등록하고 등록된 엔티티를 호출자에게 반환한다. JPA를 사용하면서 엔티티를 호출하기 위해서는 1차캐시에 없는 엔티티인 경우에도 무조건 1차캐시에 등록하고 영속화된 엔티티만 반환한다.

트렌젝션을 지원하는 쓰기지연

영속성 컨텍스트에는 쓰기지연 이라는 SQL저장소가 존재하는데 트랜잭션 commit이 될 경우 쓰기 지연 저장소에 저장된 SQL문들을 한번에 날려 여러번 해야할 반복적인 작업을 줄여주는 효과가 있다. 예를들어서 동일한 정보를 가지고 있는 엔티티를 여러번 조회할 경우 기존에는 SELECT문을 여러번 호출해야만 해당 데이터를 가져올 수 있었다. 이렇게 되면 필요 없이 데이터베이스를 호출하게 되며 자원의 낭비가 발생한다. 하지만 같은 트랜잭션 내에서 동일한 정보를 갖고 있는 객체를 호출하는 경우 해당 엔티티를 조회하는 SELECT문을 쓰기지연 저장소에 보관후 트랜젝션이 끝나는 commit시점에 쓰기지연 저장소에서 데이터베이스로 쿼리문을 한번에 날려 객체를 반환하게 된다.

이렇게 여러번 날릴것을 한번만 날리기 때문에 자원을 낭비하는 일도 적으며 무엇보다 성능적으로 이점을 챙길 수 있다.

동일성 보장

기존 데이터베이스에서 같은 ROW의 값을 가지고 여러개의 객체를 생성하여 값을 매핑하여 생성된 객체들을 동일성 비교를 하였을 때 false가 나왔었다. 왜냐하면 같은 값을 갖고 있는 객체이지만 객체가 가리키고 있는 메모리의 참조값은 다른곳을 가리키고 있기 때문이다. 하지만 영속성 컨텍스트에 등록된 엔티티는 같은 트랜잭션 이라면 엔티티를 1차캐시에 등록된 엔티티는 한번만 등록되어 반환되기 때문에 동일비교인 member1 == member2 비교를 하면 true가 나온다.

변경감지

영속화된 엔티티는 값을 변경할 때 따로 update작업을 하지 않아도 오로지 setter메소드를 통하여 값을 변경하면 영속성 컨텍스트가 알아서 인식하여 update작업을 도와주게 된다. 영속성 컨텍스트는 값의 변경이 있다면 1차 캐시에서 저장된 엔티티의 스냅샷값을 비교하여 값이 달라지게 되면 쓰기 지연 저장소에 update쿼리문을 생성하여 저장시켜둔후 커밋시점 혹은 flush시점에 한번에 쿼리문을 날리게 된다. 개발자는 따로 update작업이 필요 없으며 그저 자바의 객체 다루듯이 코딩만 하면 나머지는 JPA가 알아서 처리해준다.

flush

flush는 쓰기 지연 저장소에 있는 쿼리문을 데이터베이스로 날리는 작업을 하며 commit시점에 알아서 해주는 경우가 있거나 em.flush()와 같이 강제적으로 flush를 하는 경우강 있다.

profile
가치를 제공하는 개발자

0개의 댓글