[정리] 영속성 컨텍스트 및 엔티티
- 📚 Spring/Spring JPA
- 2022. 3. 15. 10:34
📝 엔티티 매니저 팩토리와 엔티티 매니저
- JPA가 제공하는 기능은 엔티티와 테이블을 매핑하는 설계부분과 매핑한 엔티티를 실제 사용하는 부분으로 나눌 수 있다.
- 엔티티 매니저는 엔티티를 저장하고 수정하고 삭제하고 조회하는 등 엔티티와 관련된 모든 일을 처리한다. 즉, 엔티티를 관리하는 관리자다.
- 엔티티 매니저 팩토리는 한개 만 만들어서 애플리케이션 전체에서 공유하도록 설계되어 있다.
- 엔티티 매니저 팩토리는 여러 스레드가 동시에 접근해도 안전하지만, 엔티티 매니저는 여러 스레드가 동시에 접근하면 동시성 문제가 발생하므로 스레드 간에 절대 공유하면 안된다.
- 엔티티 매니저 트랜잭션을 시작할 때 커넥션을 획득한다.
📝 영속성 컨텍스트란?
- 영속성 컨텍스트(Persistence context)는 엔티티를 영구 저장하는 환경이다.
- 엔티티 매니저로 엔티티를 저장하거나 조회화면 엔티티 매니저는 영속성 컨텍스트에 엔티티를 보관하고 관리한다.
1. 엔티티 생명주기
- 비영속 (new/transient)
- 영속 (managed) : 영속성 컨텍스트가 관리하는 엔티티
- 준영속 (detached) : 영속성 컨텍스트에 저장되었다가 분리된 상태
- 삭제 (removed)
2. 영속성 컨텍스트 특징
- 영속성 컨텍스트는 엔티티를 식별자 값으로 구분한다
- JPA는 보통 트랜잭션 커밋하는 순간 영속성 컨텍스트에 새로 저장된 엔티티를 데이터베이스에
반영하는데 이를 플러시(flush)라 한다. - 영속성 컨텍스트가 엔티티 관리할 경우의 장점
- 1차 캐시
- 동일성 보장
- 트랜잭션을 지원하는 쓰기 지연
- 변경 감지
- 지연 로딩
3. 엔티티 조회
- 영속성 컨텍스트는 내부에 캐시를 가지고 있는데 이것을 1차 캐시라 한다.
- 영속상태의 엔티티는 모두 이곳에 저장된다. 즉, 영속성 컨텍스트 내부에 Map이 하나 있는데
키는 @Id로 매핑한 식별자고 값은 엔티티 인스턴스이다. - em.find() 호출하면 먼저 1차 캐시에서 엔티티를 찾고 만약 1차 캐시에 없으면 데이터베이스에서 조회한다
4. 엔티티 등록
- 엔티티 매니저는 트랜잭션을 커밋하기 직전까지 데이터베이스에 엔티티를 저장하지 않고 내부 쿼리 저장소에 insert sql을 차곡 모아둔다. 그리고 트랜잭션을 커밋할 때 모아둔 쿼리를 데이터베이스에 보내는데 이것을 트랜잭션을 지원하는 쓰기 지연(transactional write-behind)이라 한다
- 트랜잭션을 커밋하면 엔티티 매니저는 우선 영속성 컨텍스트를 플러시한다.
- 플러시는 영속성 컨텍스트의 변경 내용을 데이터베이스에 동기화하는 작업인데 이때, 등록, 수정, 삭제한 엔티티를 데이터베이스에 반영한다.
- 이렇게 변경 내용을 데이터베이스에 동기화 한 후에 실제 데이터베이스 트랜잭션을 커밋한다.
5. 엔티티 수정
- SQL을 사용하면 데이터를 수정할 때마다 쿼리가 생성이 된다. 이런 방식의 문제는 수정 쿼리가 많아지고 비즈니스 로직을 분석하기 위해 SQL을 계속 확인해야 된다. 즉, SQL에 의존적이게 된다.
- JPA로 엔티티를 수정할 때는 단순희 엔티티를 조회해서 데이터만 변경하면 된다.
엔티티의 데이터만 변경했는데도 데이터베이스에 반영되는 이유는 엔티티의 변경사항을 데이터베이스에 자동으로 반영하는 변경감지(dirty checking) 기능 때문이다. - JPA는 엔티티를 영속성 컨텍스트에 보관할 때, 최초 상태를 복사해서 저장해두는데 이것을 스냅샷이라 한다. 그리고 플러시 시점에 스냅샷과 엔티티를 비교해서 변경된 엔티티를 찾는다
- JPA의 기본전략은 엔티티의 모든 필드를 업데이트 한다.
- 수정 시 모든 필드를 사용하면 수정쿼리가 항상 같다. 따라서 애플리케이션 로딩 시점에 수정 쿼리를 미리 생성해두고 재사용할 수 있다.
- 데이터베이스에 동일한 쿼리를 보내면 데이터베이 스는 이전에 한 번 파싱된 쿼리를 재사용할 수 있다.
6. 엔티티 삭제
- em.remove()에 삭제 대상 엔티티를 넘겨주면 엔티티를 삭제한다.
- 엔티티를 즉시 삭제하는 것이 아니라 엔티티 등록과 비슷하게 삭제 쿼리를 쓰기 지연 SQL 저장소에 등록한다.
- 이후, 트랜잭션을 커밋해서 플러시를 호출하면 실제 데이터베이스에 삭제 쿼리를 전달한다.
'📚 Spring > Spring JPA' 카테고리의 다른 글
[정리] 준영속 (0) | 2022.03.17 |
---|---|
[정리] 플러시 (flush()) (0) | 2022.03.16 |
@JsonIgnore (0) | 2020.09.04 |
[Spring JPA #12] 커스텀 리포지토리 (0) | 2020.07.22 |
[Spring JPA #11] 쿼리 실습 (0) | 2020.07.19 |