Spring

Spring Framework - Persistence Context

728x90

참조한 강의 : Spring & Hibernate For Beginners (www.udemy.com/course/spring-hibernate-tutorial/)

 

 

이번에는, 영속성 컨텍스트(Persistence Context) 와  Entity LifeCycle 이 뭔지 알아본다.

 

 

 

- Persistence Context

https://ict-nroo.tistory.com/130 , https://www.slideshare.net/RakeshKCherukuri/java-persistence-api-21/22

 

앞선 포스팅에서 Entity Class 에 대해서 언급한 적이 있었다.

Entity Class 는 DB 의 테이블과 매핑되는 클래스를 일컫는말이다.

이 Entity Class 들은 EntityManager 라는것에 의해서 관리되는데,

유저로부터 특정한 Entity 에 대한 요청이 들어올때마다,

EntityManagerFactory 라는것에서 각 Entity 에 대한 EntityManager 를 붙여준다.

 

EntityManager 에 의해 관리되는 각 Entity 들은, Persistence Context 라는곳에 담기게 되어

DB 와 연결되기 위한 영속성을 부여받는 작업을 받게되고, 영속성이 부여되면, Connection Pool 과 연결되어 DB 에 Transaction Commit 되게 된다.

 

즉, Persistence Context 는, DB 와 연결되기전 Entity 들을 담아서 영속성을 부여해서 DB 에 넣거나 혹은 DB 로 부터 테이블을 가져와서 관련된 Entity 와 매핑을 하는, Entity 를 관리하는 논리적인 어떤 Layer 라고 볼 수 있다.

Entity 들에 대한 영속성 관리를 담당하는 1차 캐시인것이다.

 

 

Persistence Context 에는 아래와 같이 두가지 타입이 존재한다

 

1) Transaction-scoped Persistence Context

https://www.baeldung.com/jpa-hibernate-persistence-context

이 영속성 컨텍스트 타입은 트랜잭션에 종속된 형태로, 트랜잭션이 종료되었을때, 엔티티들이 영속성 컨텍스트에 담기게되고, persistent storage 로 옮겨가게되는 방식이다.

영속성 컨텍스트의 기본 타입은 바로 이 Transaction-scoped Persistence Context 를 의미한다.

사용시에는 타입을 지정하지 않은 어노테이션인 @PersistenceContext 를 쓰면 된다.

@PersistenceContext
private EntityManager entityManager;
cs

 

 

2) Extended-scoped Persistence Context

https://www.baeldung.com/jpa-hibernate-persistence-context

이 타입의 영속성 컨텍스트는, 영속성 컨텍스트내에 다수의 트랜잭션이 들어갈 수 있는 형태로, 트랜잭션 없이 엔티티에 persist 할 수 있지만, 트랜잭션이 없으면 flush 는 할 수 없는 형태이다.

 

이 타입을 사용할때는 @PersistenceContext 에 타입값으로 EXTENDED 를 붙이면 된다.

@PersistenceContext(type = PersistenceContextType.EXTENDED)
private EntityManager entityManager;
cs

 

 

 

- Entity LifeCycle

https://www.udemy.com/course/spring-hibernate-tutorial/

Entity 의 생명주기는 위와 같이 4가지 상태가 존재한다

 

1) New / Transient

: 엔티티 클래스의 인스턴스만 생성한 상태로, 영속성이 전혀 부여되지 않은 상태이다.

이 인스턴스에 save 또는 persist 를 시도하면, 해당 인스턴스가 영속성 컨텍스트에 의해서 관리되는 상태로 접어들게 된다.

 

2) Persistent / Managed

: 영속성 컨텍스트에 의해서 관리되는 상태로, 이 상태에서 rollback 을 해서 관리되기 이전 상태로 되돌릴 수 있고, 트랜잭션 commit 을 시도하면 detached 상태가 되고 (detached 상태는 영속성 컨텍스트에서 분리된 상태임을 의미함) DB 로 트랜잭션 커밋되게 된다.

refresh 는 DB 의 상태와 영속성 컨텍스트 간의 상태를 동기화 시키기 위해서 쓰이는 연산이다.

 

3) Detached

: 영속성 컨텍스트에서 분리된 상태로, 더 이상 해당 엔티티가 영속성 컨텍스트에 의해서 관리되지 않는 상태이다.

여기서 다시 영속성 컨텍스트가 관리하게 하도록 넘기려면 merge 를 사용해야 한다.

 

4) Removed

: 영속성 컨텍스트에서 엔티티를 삭제한 상태로, DB 에서도 해당하는 엔티티가 삭제된다.

 

 

- Persistence Context 가 왜 필요한가

 

1) 1차 캐시

: Cache 란 자주 쓰는 데이터를 미리 복사해둔 임시 저장소를 말한다. 

캐시를 사용하는 이유는, 자주 쓰는 데이터들을 더 빠르게 접근할 수 있기 때문이다.

자주 쓰는 데이터들을 DB 에서 데이터를 조회할때 마다 DBMS 를 거쳐서 요청하는 것 보다는,

캐시에 담아뒀다가 조회하는것이 더 빠른 성능을 보여준다.

 

영속성 컨텍스트를 사용하는 이유 중 하나는, 바로 DB 에 가서 매칭되는 엔티티가 있는지 찾기보다는

1차 캐시에서 해당하는 엔티티가 있는지 찾아보면 굳이 DB 까지 가지 않더라도 캐시를 통해서 조회가 되기 때문이다.

 

 

2) 동일성 보장 

: 영속성 컨텍스트에서 엔티티들을 관리하기 때문에, 같은 엔티티들에 대해서 여러번 요청이 들어와도 똑같은 것을 참조시켜줘서 같은 엔티티를 쓰고 있음을 보장해준다.

 

 

3) 쓰기 지연

: persist 를 사용할때 바로, SQL 을 DB 로 날리는게 아니라, 트랜잭션 작업이 모두 끝마쳐지는 commit 시점에서 한번에 날린다.

https://ict-nroo.tistory.com/130

위 예시 그림에서 

처음에 persist 가 발생되서, 영속성 컨텍스트에 엔티티가 담기게 되면 (1차 캐시에 저장)

영속성 컨텍스트 내부에 있는 쓰기 지연 SQL 저장소에 쿼리들을 쌓아 놓는다.

DB 에 바로 두는게 아니라, 기다린다음, 트랜잭션이 모두 끝나는 시점에 commit 을 할때, 한번에 DB 에 모든 저장된 쿼리가 들어간다.

이때 SQL 저장소에 담긴 쿼리들이 DB 에 모두 날라가게 하는 작업을 flush 라 한다.

즉 트랜잭션 commit 을 하는 시점에 flush 가 수행되서 DB 로 쿼리가 전부 이동된 뒤에, commit 이 수행되는것.

 

- 예시 코드 (출처 : ict-nroo.tistory.com/130)

EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
// 엔티티 매니저는 데이터 변경시 트랜잭션을 시작해야 한다.
transaction.begin(); // 트랜잭션 시작
em.persist(memberA);
em.persist(memberB);
// 이때까지 INSERT SQL을 데이터베이스에 보내지 않는다.
// 커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
transaction.commit(); // 트랜잭션 커밋
cs

 

 

 

4) 변경 감지 (Dirty Check)

: 엔티티에 어떤 변화가 일어나면 영속성 컨텍스트에서 Dirty 라는 마크를 부여해서 변화된 사항을 감지한다

 

- 예시 코드 (출처 : ict-nroo.tistory.com/130)

EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin(); // 트랜잭션 시작
// 영속 엔티티 조회
Member memberA = em.find(Member.class"memberA");
// 영속 엔티티 수정
memberA.setUsername("nj");
memberA.setAge(27);
//em.update(member) 또는 em.persist(member)로 다시 저장해야 하지 않을까?
transaction.commit(); // 트랜잭션 커밋
cs

setter method 를 통해서 엔티티의 데이터를 바꾸더라도, 별도의 작업을 하지 않아도(update, persist 등) 변경사항이 저장되는 이유는,

영속성 컨텍스트 내부에는 스냅샷이란게 존재하는데, commit() 이나 flush() 가 일어날때, 엔티티에 저장된 값과 스냅샷을 비교해서 변경된 부분이 존재하면, UPDATE SQL 문을 이용해서 DB 와 연동시키기 때문이다.

 

출처 : https://ict-nroo.tistory.com/130

Dirty Check 시에 변경사항을 찾아내서 UPDATE 할때, 모든 필드를 업데이트 하도록 기본설정 되어 있다.

전체 필드를 업데이트 하는대신 변경된 일부 필드만 업데이트 하려면, @DynamicUpdate 어노테이션을 사용하면 변경 된 부분만 UPDATE 할 수 있도록 설정할 수 있다.

(참조) Dirty Checking

jojoldu.tistory.com/415

 

더티 체킹 (Dirty Checking)이란?

Spring Data Jpa와 같은 ORM 구현체를 사용하다보면 더티 체킹이란 단어를 종종 듣게 됩니다. 더티 체킹이란 단어를 처음 듣는분들을 몇번 만나게 되어 이번 시간엔 더티 체킹이 무엇인지 알아보겠습

jojoldu.tistory.com

 

 

여기까지 영속성 컨텍스트와 엔티티 생명주기에 대해서 알아봤다.

다음은, Hibernate ORM 을 통한 관계 매핑 방법에 대해 알아본다

 

 

 

 

 

- References)

1. Persistence Context : www.baeldung.com/jpa-hibernate-persistence-context

2. Hibernate Entity LifeCycle : www.baeldung.com/hibernate-entity-lifecycle

3. Cache : mangkyu.tistory.com/69

4. Transactional Write-Behind : ict-nroo.tistory.com/130

5. Flush : gmlwjd9405.github.io/2019/08/07/what-is-flush.html

6. Dirty Checking : jojoldu.tistory.com/415

 

 

728x90

'Spring' 카테고리의 다른 글

Spring Framework - 연관 관계 매핑  (0) 2021.02.13
Spring Framework - Eager, Lazy Loading  (0) 2021.02.11
Spring Framework - CRUD Using Hibernate ORM  (0) 2021.02.04
Spring Framework - Hibernate ORM  (0) 2021.02.02
Spring Framework - Validation  (0) 2021.02.01