본 글은, 자바 ORM 표준 JPA 프로그래밍(김영한님) 책을 요약 정리한 포스팅입니다.
- 실무에서 필요한JPA - 영속성 관리(1)
- 실무에서 필요한JPA - 엔티티 매핑(2)
- 실무에서 필요한JPA - 연관관계 매핑(기초)(3)
- 실무에서 필요한JPA - 다양한 연관관계매핑(4)
- 실무에서 필요한JPA - 프록시와 연관관계(5)
- 실무에서 필요한JPA - 값타입(6)
- 실무에서 필요한JPA - 객체지향 쿼리(7)
- 실무에서 필요한JPA - 스프링 데이터 JPA(8)
- 실무에서 필요한JPA - 컬렉션과 부가기능(9)
- 실무에서 필요한JPA - 고급주제와 성능 최적화(10)
- 실무에서 필요한JPA - 트랜잭션과 락 2차 캐시(11)
실무에서 필요한JPA - 영속성 관리(1)
학습목표
- EntityMangerFacotry와 EntityManager의 관계를 이해한다.
- PersistenceContext(영속성 컨텍스트)의 특징을 이해하고, CRUD에서 어떻게 동작하는지를 이해한다.
- 영속성 컨텍스트가 관리하는 엔티티의 생명주기를 이해한다.
- Flush에 대해서 알아본다.
- 준영속 상태의 특징을 이해한다.
엔티티 매니저 팩토리와 엔티티 매니저
- EntityManagerFactory는 EntityManager를 만드는 공장인데, 공장을 만드는 비용은 상당히 크다. 따라서 싱글턴으로 만들어서 웹 애플리케이션에서 공유하도록 설계되어있다.
- EntityMangaer는 데이터베이스 연결이 꼭 필요한 시점까지 커넥션을 얻지 않는다. (Lazy). 트랜잭션을 시작할때 커넥션을 획득한다.
- Hibernate를 포함한 JPA 구현체들은 EntityManagerFactory를 생성할 때 커넥션 풀도 만든다.
영속성 컨텍스트(Persistence Context)
- JPA를 이해하는데 가장 중요한 핵심
- 엔티티를 영구히 저장하는 환경정도라고 이해하면 된다.
- EntityManager를 생성할때 영속성 컨텍스트가 만들어진다.
- EntityManger를 통해서 영속성 컨텍스트에 접근하거나 관리할 수 있다.
엔티티 생명주기
- 비영속 (new/transient): 전혀 관계가 없는 상태
- 영속(managed): 영속성 컨텍스트에 저장된 상태
- 준영속(detached): 저장되었다가 분리된 상태
- 삭제(remove): 삭제된 상태
출처: 자바 JPA 프로그래밍(김영한)
영속성 컨텍스트의 특징
- 영속성 컨텍스트는 엔티티를 식별자 값(@Id로 매핑한 값) 으로 구분한다. 영속상태는 식별자 값이 반드시 있어야 한다. 없으면 예외가 발생한다.
- 영속성 컨텍스트와 데이터 베이스 저장. JPA는 보통 트랜잭션을 커밋하는 순간, 영속성컨텍스트에 새로 저장된 엔티티를 데이터베이스에 반영한다(Flush)
- 영속성 컨텍스트의 장점
- 1차 캐시
- 동일성 보장
- 트랙잭션을 지원하는 쓰기 지연
- 변경 감지
- 지연 로딩
엔티티 조회
- em.find(Member.class, “member1”)를 호출하고, 1차 캐시를 먼저 찾는다.
- 없으면 데이터베이스에서 조회하고, 조회한 데이터를 1차캐시에 저장한다.
- 이후에 member1로 조회하게되면 영속성 컨텍스트에서 식별자를 통해서 해당 엔티티를 반환한다. (캐쉬가 동작하는 원리)
엔티티 등록
em.persist(memberA)
까지는 INSERT SQL문을 데이터베이스에 보내지 않는다.transaciton.commit()
커밋하는 순간에 보낸다. → 성능최적화에서 다룬다.✅- EntityManager는 트랜잭션을 커밋하기 직전까지 내부 쿼리 저장소에 INSERT SQL을 모아둔다. 그리고 트랜잭션을 커밋할때 모아둔 쿼리를 데이터베이스에 보내는데, 이를 트랜잭션을 지원하는
쓰기 지연
이라 한다.
- EntityManager는 트랜잭션을 커밋하기 직전까지 내부 쿼리 저장소에 INSERT SQL을 모아둔다. 그리고 트랜잭션을 커밋할때 모아둔 쿼리를 데이터베이스에 보내는데, 이를 트랜잭션을 지원하는
- 트랜잭션을 커밋하면 EntityManger는 우선 영속성 컨텍스트를 Flush한다. Flush는 영속성 컨텍스트의 변경 내용을 데이터베이스에 동기화 하는 작업이다.
엔티티 수정(변경 감지)
- JPA로 엔티티를 수정할 때는 엔티티를 조회해서, 데이터만 변경하면 된다.이렇게 엔티티의 변경사항을 데이터베이스에 자동으로 반영하는 기능을
변경감지
(Dirty checking) - JPA는 엔티티를 영속성 컨텍스트에 보관할 때, 최초 상태를 복사해서 저장해두는데 이것을 스냅샷이라고 한다. Flush 시점에 스냅샷과 엔티티를 비교해서 변경된 엔티티를 찾는다.
- 변경감지는 영속성 컨텍스트가 관리하는 영속 상태의 엔티티에만 적용된다.
- JPA의 기본전략은 엔티티의 모든 필드를 업데이트 한다.
- 모든 필드를 사용하면, 데이터 전송량이 증가하는 단점이 있지만 다음과 같은 장점으로 인해 모든 필드를 업데이트 한다.
- 모든 필드를 사용하면 수정 쿼리는 항상 같다. 애플리케이션 로딩 시점에 수정 쿼리를 미리 생성해두고 재사용 가능하다.
- 데이터베이스에 동일한 쿼리를 보내면 데이터베이스는 이전에 한 번 파싱된 쿼리를 재사용 할 수 있다.
- 모든 필드를 사용하면, 데이터 전송량이 증가하는 단점이 있지만 다음과 같은 장점으로 인해 모든 필드를 업데이트 한다.
- 만약에, 필드가 너무 많거나 저장되는 내용이 너무 크면
수정된
데이터만 사용해서 동적으로 UPDATE SQL를 생성하는 전략을 선택하면 된다. 이때는 하이버네이트 확장 기능을 사용해야 한다.
@Entity
@org.hibernate.annotations.DynamicUpdate
@Table
public class Member {...}
엔티티 삭제
- 엔티티 등록과 비슷하게 삭제 쿼리를 쓰기 지연 SQL 저장소에 등록한다. 이후 트랜잭션 커밋해서, 플러시를 호출하면 실제 데이터베이스에 삭제 쿼리를 전달한다.
플러시(Flush)
- 플러시는 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영한다.
- 영속성 컨텍스트를 플러시 하는 방법
- em.flush()를 직접 호출한다. (거의 사용하지 않는다.)
- 트랜잭션 커밋시 플러시가 자동 호출된다. (JPA는 트랜잭션을 커밋할때)
- JPQL쿼리 실행 시 플러시가 자동 호출된다.
- 플러시 모드 옵션
- javax.persistence.FlushModeType를 사용한다.
em.setFlusMode(FlushModeType.COMMIT)
직접 설정- FlushModeType.AUTO: 커밋이나 쿼리를 실행할때 플러시(기본값)
- FlushModeType.COMMIT: 커밋할 때만 플러시
- javax.persistence.FlushModeType를 사용한다.
준영속
- 영속성 컨텍스트가 관리하는 영속상태의 엔티티가 영속성 컨텍스트에서 분리된 것을 준영속 상태라 한다. 준영속 상태 엔티티는 영속성 컨텍스트가 제공하는 기능을 사용할 수 없다.
- 준영속 상태로 만드는 방법
- em.detach(entity): 특정 엔티티만 준영속 상태로 전환한다.
- em.clear(): 영속성 컨텍스트를 완전히 초기화한다.
- em.close(): 영속성 컨텍스트를 종료한다.
- 1차캐시, 쓰지지연 저장소등이 존재하지 않는다. 종료되었다.
- 준영속 상태의 특징
- 거의 비영속 상태에 가깝다. 영속성 컨텍스트가 제공하는 1차 캐시, 쓰기 지연, 변경감지, 지연로딩 어떠한 기능도 동작하지 않음
- 식별자 값을 가지고 있다.
- 지연로딩을 할 수 없다.
- 병합: merge()
- 준영속 상태의 엔티티를 다시 영속 상태로 변경하려면 병합을 사용하면 된다.
정리
- 엔티티 매니저는 엔티티 매니저 팩토리에서 생성한다. J2SE환경에서는 엔티티 매니저를 만들면 그 내부에서 영속성 컨텍스트도 함께 만들어진다.
- 영속성 컨텍스는 애플리케이션과 데이터베이스 사이에서 객체를 보관하는 가상의 데이터베이스 역할을 한다. 덕분에
1차캐시
,동일성 보장
트랜잭션을 지원하는쓰기지연
,변경 감지
,지연로딩
기능을 사용할 수 있다. - 영속성 컨텍스트에 저장한 엔티티는 플러시 시점에 데이터베이스에 반영되는데, 일반적으로 트랜잭션을 커밋할 때 영속성 컨텍스트가 플러시 된다.
- 영속성 컨텍스트의 관리를 받지 못하는 엔티티를
준영속 상태
라 하고, 이는 영속성 컨텍스트가 제공하는 1차 캐시, 동일성 보장, 쓰기지연, 변경감지, 지연로딩 같은 기능을 사용할 수 없다.
📚 Related Posts
- JPA - 값 타입(6)
- JPA - 프록시와 연관관계(5)
- JPA - 다양한 연관관계 매핑(4)
- JPA - 연관관계 매핑(기초)(3)
- JPA - 엔티티 매핑(2)
- JPA - 영속성 관리(1)
- [JPA] 연관관계 매핑 (연관관계 편의 메서드)
- [JPA] 엔티티 설계시 주의사항들
- [JPA] Auditing 사용하기
- [JPA]@Transactional를 통한 Optimization
- [JPA] 엔티티 일부 데이터만 조회하는 Projection
- [JPA] save메서드로 살펴보는 persist와 merge 개념
- [JPA] 쿼리메서드(Lookup 전략)
- [JPA] QueryDSL 설정방법
- [JPA] null 처리
- [JPA] 연관관계 매핑 기초(다대일, 연관관계 주인)
- SpringBoot, JPA, H2를 이용한 간단한API 작성
- [JPA] proxy, fetch 전략
- [JPA] 도메인 클래스 컨버터란?
- [JPA] Custom Repository 만들기
- [JPA] Casecade 옵션