[JPA] 영속성 컨텍스트
07 Jun 2022해당 포스트는 인프런 김영한님의 자바 ORM 표준 JPA 프로그래밍 - 기본편 을 듣고 정리한 글입니다.
영속성 컨텍스트 (Persistent)
JPA를 이해하는데 가장 중요한 용어이며, “엔티티를 영구 저장하는 환경” 이라는 뜻이다, JPA를 다루면서 자주 만나게 될 단어이므로 개념을 확실하게 챙겨가도록 하자.
EntityManager.persist(entity);
를 이용해 Entity를 영속성 컨텍스트에 저장을 한다. (DB에 바로 저장하는 것이 아니다.)
EntityManager와 영속성 컨텍스트
- 영속성 컨텍스트는 논리적인 개념이다.
- 눈에 보이지 않으며, 엔티티 매니저를 통해 영속성 컨텍스트에 접근한다.
기본적인 J2SE 환경에서는 1:1로 매핑되어 있다. 컨테이너 환경의 EntityManager는 추후 다시 설명하도록 한다.
엔티티의 생명주기
-
비영속 (new/transient) 영속성 컨텍스트와 전혀 관계가 없는 새로운 상태
-
영속 (managed) 영속성 컨텍스트에 관리되는 상태
EntityManager.persist(entity);
를 할시에 해당 상태로 변경된다. -
준영속 (detached) 영속성 컨텍스트에 저장되었다가 분리된 상태
-
삭제 (removed) 삭제된 상태
해당 그림은 엔티티의 생명주기로써 그림을 참고하도록 하자.
비영속
객체를 생성한 상태이지만, 영속 컨텍스트에 들어가지 않은 말한다.
/* 객체를 생성한 상태(비영속) */
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
영속
객체를 생성한 후에, EntityManager를 불러 영속성 컨텍스트에 집어 넣은 상태를 말한다.
/* 객체를 생성한 상태(비영속) */
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("hello");
EntityManager entityManager = entityManagerFactory.createEntityManager();
em.getTransaction().begin();
/* 객체를 저장한 상태 (영속) */
entityManager.persist(member);
...
영속상태는 DB에 저장된 상태가 아니다. 실제 저장되는 상태는, 트랜잭션이 commit을 하는 시점에 SQL를 만들어 실행한다. 아래의 예시를 통해 SQL 쿼리 시점을 확인해보자.
/* 실행 예제 */
Member member = new Member();
member.setId(101L);
member.setName("Hello JPA");
System.out.println("=== PERSISTENT BEFORE ===");
entityManager.persist(member);
System.out.println("=== PERSISTENT AFTER ===");
entityTransaction.commit();
=== PERSISTENT BEFORE ===
00:52:26.089 [main] DEBUG org.hibernate.event.internal.AbstractSaveEventListener - Generated identifier: 101, using strategy: org.hibernate.id.Assigned
=== PERSISTENT AFTER ===
00:52:26.107 [main] DEBUG org.hibernate.engine.transaction.internal.TransactionImpl - committing
00:52:26.107 [main] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener - Processing flush-time cascades
00:52:26.108 [main] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener - Dirty checking collections
00:52:26.113 [main] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener - Flushed: 1 insertions, 0 updates, 0 deletions to 1 objects
00:52:26.114 [main] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener - Flushed: 0 (re)creations, 0 updates, 0 removals to 0 collections
00:52:26.115 [main] DEBUG org.hibernate.internal.util.EntityPrinter - Listing entities:
00:52:26.116 [main] DEBUG org.hibernate.internal.util.EntityPrinter - com.dhaudgkr.jpastart.hellojpa.entity.Member{name=Hello JPA, id=101}
00:52:26.123 [main] DEBUG org.hibernate.SQL -
/* insert com.dhaudgkr.jpastart.hellojpa.entity.Member
*/ insert
into
Member
(name, id)
values
(?, ?)
위의 예제를 확인하면, entityManager.persist(member);
코드에서 쿼리를 날리는것이 아닌, 트랜잭션이 commit 이후 insert 쿼리를 만들어 날리는것을 확인 할 수 있다.
준영속, 삭제
삭제의 경우 실제 DB에 delete 쿼리를 요청하는 메서드이다.
/* 회원 엔티티를 영속성 컨텍스트에서 분리, 준영속 상태 */
entityManager.detach(member);
/* 객체를 삭제한 상태 (삭제) */
entityManager.remove(member);