개발이 취미인 사람

[JPA] - 영속성 컨텍스트(1) 본문

백앤드(Back-End)/Jpa

[JPA] - 영속성 컨텍스트(1)

RyanSin 2024. 11. 24. 22:12
반응형

개요

안녕하세요. 이번 시간에는 JPA 영속성 컨텍스트에 대해 알아보겠습니다.

 

지난 시간 내용을 학습하고 오시지 못하신 분들은 학습하고 오시는 걸 추천드리겠습니다.

 

[JPA] - 기본 동작 방식과 단순 CRUD

 

[JPA] - 기본 동작 방식과 단순 CRUD

개요안녕하세요. 이번 시간에는 JPA에서 기본적인 동작방식에 대해 알아보겠습니다. 기본 동작 방식JPA에는 기본적으로 Persistence 라는 클래스를 통해 설정 정보를 가져와 EntityManagerFactory를 만듭

any-ting.tistory.com

 

 

영속성 컨텍스트란?

영속성 컨텍스트라는 단어를 딱 들었을 때 무슨 말이 생각이 나시나요? 저는 머릿속에 잘 그려지지 않아 무식하게 그림으로 외웠던 같아요.

 

간단하게 말해서 영속성은 데이터를 오랫동안 유지하는 성질 또는 능력을 의미하며, 컨텍스트는 특정 상황이나 환경에서의 맥락 또는 상황적 정보를 의미합니다.

 

그럼 JPA에서 영속성 컨텍스트란 무엇일까요? 엔티티를 DB에 저장하기 전까지 임시로 관리하는 공간을 말합니다.

 

실제 물리적인 DB가 아닌 임시 저장소라고 생각하면 됩니다. 어찌보면 엔티티 객체를 관리하는 JPA 캐시라고도 표현할 수 있습니다.

 

지난 시간에 EntityManagerFactory와 EntityManager에 대해 가볍게 살펴봤습니다.

 

EntityManagerFactory를 통해 EntityManager를 생성합니다. 우리는 하나의 EntityManager를 통해 PersistenceContext를 생성합니다. 

 

 

 

하나의 커넥션 단위를 EntityManager를 통해 생성이 된다고 지난시간에 설명을 했습니다. EntityManager와 PersistenceContext의 동작 원리를 하나씩 살펴보겠습니다.

 

엔티티 생명주기

  1. 비영속(new/transient) - 영속성 컨텍스트와 전혀 관계가 없는 새로운 상태
  2. 영속(managed) - 영속성 컨텍스트에 관리되는 상태
  3. 준영속(detached) - 영속성 컨테스트에 저장되었다가 분리된 상태
  4. 삭제(removed) - 엔티티가 삭제된 상태

위 생명준기 관련된 내용은 지난 시간 코드를 가지고 설명하도록 하겠습니다.

 

1. 비영속 상태

비영속 상태는 객체를 생성한 상태를 말합니다. 실제 영속성 컨텍스트에 등록되기 전 상태를 말합니다.

 

비영속 상태

2. 영속 상태

영속 상태는 영속성 컨텍스트에 엔티티를 등록한 상태를 말합니다.

EntityManager를 통해 persist(entity) 메서드를 호출하면 영속성 컨테스트에 엔티티가 등록됩니다.

영속 상태

 

여기서 중요한 부분은 persist() 메서드를 호출할 때 실제 DB에 데이터를 저장하는 게 아닌 영속성 컨텍스트에 저장만 합니다.

실제 DB에 데이터를 저장은 트랜잭션을 커밋하는 시점에 쿼리가 수행됩니다.

 

하지만 우리가 Entity 설정시 @GenerateValue 어노테이션을 GenerationType.IDENTITY 로 설정했기 때문에 트랜잭션을 시작하고 persist() 메서드가 호출시 쿼리가 실행됩니다.

 

 

3. 준영속 상태

준영속 상태는 단순합니다. 영속성 컨텍스트에 등록된 엔티티를 분리하면 준영속 상태가 됩니다.

 

detach() 메서드를 활용하면 등록된 엔티티를 분리할 수 있습니다.

 

다른 방법으로는 영속성 컨텍스트를 초기화(em.clear()) 하거나 영속성 컨텍스트를 종료(em.close())하면 당연히 완전 초기화 되기 때문에 준영속 상태가 됩니다.

 

fun setDetach(member: MemberEntity) {
    this.em.detach(member)
}

 

실제 확인하고 싶으면 다음 코드를 실행하면 확실히 이해할 수 있습니다.

package com.ryan.kotlinspirngjpa.jpa.repository

import com.ryan.kotlinspirngjpa.jpa.entity.MemberEntity
import jakarta.persistence.EntityManager
import jakarta.persistence.EntityManagerFactory
import jakarta.persistence.Persistence
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeEach
import kotlin.test.Test
import kotlin.test.assertNotEquals

class PersistenceContextTest {
    private lateinit var emf: EntityManagerFactory
    private lateinit var em: EntityManager
    private lateinit var memberRepository: MemberRepository

    @BeforeEach
    fun setUp() {
        this.emf = Persistence.createEntityManagerFactory("ryan")
        this.em = this.emf.createEntityManager()
        this.memberRepository = MemberRepository(this.em)
    }

    @AfterEach
    fun closeEntityManager() {
        if (::em.isInitialized) {
            em.close()
        }

        if (::emf.isInitialized) {
            emf.close()
        }
    }

    @Test
    fun `Detach 준영속 상태 만들기`() {
        // given(준비): 어떠한 데이터가 준비되었을 때
        val member = MemberEntity(name = "HelloA")
        this.memberRepository.save(member)

        val findMember = this.memberRepository.findById(1L)
        findMember!!.name = "HelloB"

        // when(실행): 어떠한 함수를 실행하면
        this.memberRepository.setDetach(findMember)

        // then(검증): 어떠한 결과가 나와야 한다.
        val updateMember = this.memberRepository.findById(1L)!!

        //updateMember.name 값은 HelloA
        assertNotEquals(findMember.name, updateMember.name)
    }
}

 

하나의 member를 생성한 후 member entity에서 조회한 뒤 update 쿼리가 실행되길 원하겠짐나 실제로는 update 쿼리는 실행되지 않습니다. 왜냐면 준영속성 상태로 변경되었기 때문입니다.

 

4. 삭제

삭제는 대상 엔티티를 조회한 후 remove(entity) 메서드를 호출할면 실제 delete 쿼리가 실행됩니다.

fun delete(member: MemberEntity) {
    this.em.transaction.begin()
    try {
        this.em.remove(member)
        this.em.transaction.commit()
    } catch (e: Exception) {
        this.em.transaction.rollback()
    }
}

 

 

이번 시간에는 영속성 컨텍스트에 대한 개념과 엔티티 생명주기에 대해 알아봤습니다.

 

실습을 꼭 해보시는 걸 추천드리겠습니다.

 

Github

 

GitHub - Ryan-Sin/kotlin-spring-jpa: 코프링 환경에서 기본 jpa부터 spring-data-jpa를 사용하는 방법에 대해

코프링 환경에서 기본 jpa부터 spring-data-jpa를 사용하는 방법에 대해 학습합니다. - Ryan-Sin/kotlin-spring-jpa

github.com

 

'백앤드(Back-End) > Jpa' 카테고리의 다른 글

[JPA] - Entity 관계 설정 방법  (1) 2024.12.24
[JPA] - Entity 정의 방법  (3) 2024.12.14
[JPA] - 영속성 컨텍스트(2)  (2) 2024.11.29
[JPA] - 기본 동작 방식과 단순 CRUD  (0) 2024.11.19