BackEnd/JPA

[JPA] 영속성 관리

JJangGu 2022. 5. 3. 01:29

이번에는 영속성 관리에 대한 이야기를 해보겠습니다. 영속성이라는 것은 영어로 표현했을 시, Persistence 입니다. JPA 가 Java Persistence API 인 것을 보면 이 개념이 중요하다는 것을 알 수 있습니다.

 

영속성 컨텍스트 

엔티티를 영구 저장하는 환경. 엔티티 매니저로 엔티티를 저장하거나 조회하면 엔티티 매니저는 영속성 컨텍스트에 엔티티를 보관, 관리한다.

 

영속성 컨텍스트를 개발을 하면서 직접 볼 일은 없다고 생각됩니다. 엔티티 매니저를 통해서 접근하고 관리할 수 있지만, Spring Data JPA 를 사용한다면 이것마저도 개발자가 크게 신경쓸 일이 없습니다. 

하지만 엔티티의 생명주기와 1차 캐시, 변경 감지, 지연 로딩 등 여기서 부터 출발하는 개념이 상당하고, JPA 를 이해하는데 반드시 알아야 한다고 생각합니다.

 

코드를 보면, 엔티티 매니저를 통해 접근,관리한다는 내용이 좀 더 쉽게 이해가 됩니다.

엔티티매니저를 통해서 트랜잭션이 시작되고 끝나며, 그 안에 persist() 를 통해서 엔티티를 영속성 컨텍스트에 저장하는 내용이 담긴 코드입니다. 

EntityManagerFactory emf = Persistence.createEntityManagerFactory("");

EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin();

Member newMember = new Member();
newMember.setId("member2");
newMember.setName("name");
em.persist(newMember);

Member member = em.find(Member.class, "member1");
member.setName("changedName");

transaction.commit();

 

Persistence.createEntityManagerFactory("name");

META-INF/persistence.xml 에 있는 정보를 바탕으로 EntityManagerFactory 를 생성합니다. 팩토리이므로 어플리케이션이 실행될때, 한번 생성해서 공유되고 여러 스레드가 접근해도 안전합니다. 

 

엔티티 매니저는 팩토리를 통해서 생성하면 됩니다. 필요한 시점(보통 트랜잭션을 시작할 때)에 connection을 줘서 사용하게 되고, 여러 스레드가 동시 접근하면 동시성 문제가 발생됩니다. 

 

위의 그림을 보면, EntityManagerFactory 가 다수의 EntityManager 를 생성하고, 매니저는 필요한 시점에 커넥션을 얻어 사용한다는 것이 이해가 됩니다.

 

다음으로는 생명주기입니다.

 

🔄 엔티티의 생명주기(상태) 

엔티티의 생명주기라고 하지만, 상태로 이해하는것이 더 쉽게 와닿는 것 같습니다.

엔티티에는 4가지의 상태가 존재합니다.

 

  • 1. 비영속 (new) : 영속성 컨텍스트와 관계가 없는 상태
  • 2. 영속 (managed) : 영속성 컨텍스트에 저장된 상태
  • 3. 준영속 (detached) : 영속성 컨텍스트에 저장이 되었다가 분리된 상태
  • 4. 삭제 (removed) : 영속성 컨텍스트에서 삭제된 상태

 

 

위 그림이 엔티티의 생명주기와 상태를 나타낸 그림입니다.

 

먼저 비영속 상태를 보겠습니다. 이때는 객체 상태이며 아직 영속성 컨텍스트에는 저장이 되지않아서 데이터베이스와도 관련이 없습니다.

Member newMember = new Member();
newMember.setId("member2");
newMember.setName("name");

 

위와 같이 흔히 보던 객체의 모습입니다. 

 

이제 영속 상태를 보면, 위의 객체가 영속성 컨텍스트에 저장된 상태를 말합니다. 그 말은 이제는 영속성 컨텍스트에 의해 관리된다는 뜻입니다. 위의 상태에서 persist() 를 통해서 영속성 컨텍스트에 객체(엔티티)를 올릴 수 있습니다.

 

em.persist(member);

 

영속성 컨텍스트는 엔티티를 식별자 값으로 구분을 합니다. 따라서 영속 상태는 식별자 값이 반드시 있어야 하고, 없다면 예외가 발생합니다. 영속성 컨테스트의 엔티티를 저장하면 JPA 는 트랜잭션을 커밋하는 순간 영속성 컨텍스트에 저장된 엔티티를 데이터베이스에 반영하고, 이를 flush 라고 합니다. 

 

영속성 컨텍스트에 엔티티가 올라온김에 잠깐 특징을 살짝 이야기 했습니다. 다음으로, 준영속 상태와 삭제 상태를 살펴보겠습니다.

em.detach(member);

이렇게 detach() 를 통해서 준영속 상태로 만들 수 있습니다. 이는 엔티티를 영속성 컨텍스트에서 관리하지 않는 것을 의미하고, em.close() 로 영속성 컨텍스트를 닫거나, clear() 로 초기화해도 영속 상태의 엔티티는 준영속 상태가 됩니다.

 

em.remove(member);

remove()를 통해서 영속성 컨텍스트와 데이터베이스에서 삭제를 할 수도 있습니다.

 

위의 그림을 잠깐 짚어보자면, 어떤 엔티티 객체를 new 로 생성하면 비영속 상태에서 시작합니다. 그 후 persist 를 통해 영속성 컨텍스트에 올라간 managed 상태가 되고, 이 상태에서 flush 가 일어난다면 DB 에 영속성 컨텍스트의 내용이 반영됩니다. 만약 flush 가 일어나기 전에 컨텍스트에서 관리를 할 것이 아니면 detach 를 통해 준영속이나 remove 를 통해 삭제하면 되겠습니다.

 

그러면 이렇게 영속성 컨텍스트를 사용했을 때 얻은 장점에 대해서도 짚어보겠습니다.

 

✨ 영속성 컨텍스트가 엔티티를 관리할 때 얻는 장점

  • 1차 캐시
  • 일성 보장
  • 트랜잭션을 지원하는 쓰기 지연
  • 변경 감지
  • 지연 로딩

이 장점들에 대해서는 내용이 길어질 것 같아 다음글부터 살펴보겠습니다. 또한 엔티티의 상태에서도 부가 설명이 필요한 부분을 보충하겠습니다.