티스토리 뷰

Framework/Spring

[JPA] 영속성

DUCKBAE's 2022. 8. 9. 13:53

영속성

데이터를 생성한 프로그램의 실행이 종료되더라도 사라지지 않는 데이터의 특성을 의미한다.

 

영속성 컨텍스트 (Persistence Context)

Entity를 영구 저장하는 환경이다.

애플리케이션이 데이터베이스에서 꺼내온 객체를 보관하는 역할을 한다.

  • 영속성 컨텍스트는 Entity Manager를 생성할 때 하나 만들어진다.
  • 영속성 컨텍스트는 Entity Manager를 통해 Entity를 조회하거나 저장할 때 Entity를 보관하고 관리한다.

 

Entity 생명주기

비영속 (New/Transient)

영속성 컨텍스트와 관계가 없는 상태 (순수한 객체 상태)

Member member = new Member();
member.setId("1");
member.setName("김세영");

 

영속 (Managed)

영속성 컨텍스트에 저장된 상태

* DB에 저장하려면 commit 혹은 flush 를 진행해야 한다.

entityManager.persist(member);

 

준영속 (Detached)

영속성 컨텍스트에 저장되었다가 분리된 상태

- 준영속 상태가 되면 1차 캐시부터 쓰기 지연 SQL 저장소까지 해당 Entity를 관리하기 위한 모든 정보가 삭제된다.

entityManager.detach(member); //영속성 컨텍스트에서 분리
entityManager.closed(); //영속성 컨텍스트 종료
entityManager.clear(); //영속성 컨텍스트 비우기

 

삭제 (Removed)

영속성 컨텍스트와 데이터베이스에서 삭제된 상태

entityManager.remove();

 

영속성 컨텍스트의 특징

영속성 컨텍스트와 식별자 값

영속성 컨텍스트는 엔티티를 식별자 값(@Id로 테이블의 기본 키와 매핑한 값)으로 구분한다.
따라서 영속 상태는 식별자 값이 반드시 있어야 한다. 식별자 값이 없으면 예외 발생!

 

영속성 컨텍스트와 데이터베이스 저장

JPA는 보통 트랜잭션을 커밋하는 순간 영속성 컨텍스트에 새로 저장된 엔티티를 데이터베이스에 반영하는데 이것을 플러시라고 한다.

 

영속성 컨텍스트의 이점

1차 캐시

영속성 컨텍스트는 내부에 캐시를 가지고 있는데, 이것을 1차 캐시라고 한다.

entityManager.persist(member); //영속성 컨텍스트 1차 캐시에 저장

Member resMember = entityManager.find(Member.class, "1"); //1차 캐시에서 조회

 

만약 1차 캐시에 데이터가 없을 경우, DB에서 직접 조회한 후 1차 캐시에 저장하고 반환한다.

(1차 캐시에 데이터가 있다면 DB에서 조회하지 않고 1차 캐시에서 엔티티를 반환한다.)

요청이 시작되면 영속성 컨텍스트를 생성하고, 요청이 끝나면 영속성 컨텍스트를 지운다.

이 때, 1차 캐시도 삭제된다.

따라서 어플리케이션 전체에 공유하는 것이 아니다. (어플리케이션 전체에 공유하는 캐시는 2차 캐시이다.)

 

동일성 보장 (Identity)

Member member1 = entityManager.find(Member.class, "1");
Member member2 = entityManager.find(Member.class, "1");

System.out.print(member1 == member2); // true

영속성 컨텍스트에 해당 객체가 존재한다면 여러번 해당 객체를 find 하더라도 1차 캐시에 있는 인스턴스를 반환한다.

따라서 영속 엔티티에 대한 동일성을 보장한다.

 

 

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

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

Member member1 = new Member("1", "김세영");
Member member2 = new Member("2", "홍길동");

transaction.begin(); //트랜잭션 시작

entityManager.persist(member1);
entityManager.persist(member2);

transaction.commit(); //트랜잭션 커밋

엔티티 매니저는 트랜잭션을 커밋하기 전까지 1차 캐시에 저장 후 동시에 쓰기 지연 쿼리 저장소에 INSERT 명령문을 저장한다.

그리고 나서 트랜잭션을 커밋할 때 쓰기 지연 쿼리 저장소에 모아둔 쿼리를 데이터베이스에 보내는데 이것을 쓰기 지연이라 한다.

* 트랜잭션을 커밋하면 Entity Manager는 영속성 컨텍스트를 플러시 하는데, 여기서 플러시는 영속성 컨텍스트의 변경 내용을 DB에 에 동기화하는 작업을 말한다.

 

변경감지 (Dirty Checking)

변경 감지는 영속성 컨텍스트가 관리하는 영속 상태의 엔티티에만 적용된다.

transaction.begin();

Member member = entityManager.find(Member.class, "1"); //영속 엔티티 조회 & 스냅샷 생성
member.setName("홍길동");

transaction.commit();

엔티티를 수정할 때 update(), persist() 와 같은 메서드로 영속성 컨텍스트에 알려주지 않아도 된다.

* update() 메서드는 제공하지 않을 뿐더러 변경감지를 통해 엔티티를 수정할 수 있기 때문이다.

단지 엔티티를 조회하고 데이터만 변경해주면 된다.

엔티티는 영속 컨텍스트에 저장될 때 스냅샷(최초 상태를 복사)을 생성한다.

그리고 플러시 시점에 변경된 엔티티와 스냅샷과 비교하여 객체가 변경되었다면 수정 쿼리를 생성하고 쓰기 지연 쿼리 저장소에 저장한다.

 

 

참고

자바 ORM 표준 JPA 프로그래밍 - 김영한

'Framework > Spring' 카테고리의 다른 글

[Spring] Singleton Container  (0) 2022.08.22
[Spring] Container  (0) 2022.08.17
[JPA] JPA  (0) 2022.08.08
[JPA] View Table  (0) 2022.07.28
[JPA] Composite Key  (0) 2022.07.22
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함