JPA ) 자바 ORM 표준 JPA 프로그래밍 - 3

GoRuth·2025년 4월 14일

JPA

목록 보기
3/8

1. EntityManagerFactory & EntityManager

  • DB를 하나만 사용한다면 Application은 일반적으로 하나의 EntityManagerFactory를 생성한다.
  • 이제, 필요할 때마다 EntityManager를 생성하면 된다.

💡 EntityManagerFactory

  • 만드는 비용이 상당히 큼 -> Application 전체에서 공유하고록 설계
  • 여러 Thread가 동시 접근해도 안전 -> 서로 다른 Thread간 공유 가능

💡 EntityManager

  • Factory에서 생성하는 비용이 거의 안듬
  • 여러 Thread가 접근하면 동시성 문제 발생 -> 절대 공유 X
  • DB연결이 실제로 필요한 시점(트랜잭션 시작 시점)까지 DB 커넥션을 얻지 않음!
    -> 보통 Transaction 시작할 때 커넥션 획득


2. 영속성 컨텍스트 (persistence context)?

  • 엔티티를 영구저장하는 환경
  • 그 동안 사용했던 persist(Object o)는 단순 DB저장 ❌
    -> 엔티티 매니저를 사용, 회원 엔티티를 영속성 컨텍스트에 저장 ⭕

3. 엔티티의 생명주기

3.1. 비영속 (new/transient)

  • 영속성 컨텍스트와 전혀 관계가 없는 상태
  • 객체 생성 후 persist() 호출 전 -> 순수한 객체상태

3.2. 영속 (managed)

  • 영속성 컨텍스트에 저장된 상태
    -> 영속성 컨텍스트에 의해 관리
  • EntityManager를 통해 Entity를 영속성 컨텍스트에 저장
    • persist()

3.3. 준영속 (detached)

  • 영속성 컨텍스트에 저장되었다가 분리된 상태
  • 준영속으로 만드는 법
    • detach()로 분리
    • close()를 통해 닫기
    • clear()로 초기화

3.4. 삭제 (remove)

  • DB 삭제가 예정된 상태 (remove() 호출 후 트랜잭션 커밋 전 상태)
  • 삭제하는 법
    • remove()로 삭제

4. 영속성 컨텍스트의 특징

4.1. 식별자 필수!

  • 영속성 컨텍스트는 식별자로 구분
    • 영속 상태는 식별자가 무조건 있어야 함!
    • 없다면 Error

4.2. Flush

  • 보통 트랜잭션을 커밋하는 순간 영속성 컨텍스트에 새로 저장된 엔티티를 데이터베이스에 동기화하는 작업

  • 실행하면 생기는 일

    1. 변경 감지가 동작, 영속성 컨텍스트에 있는 모든 엔티티를 스냅샷과 비교해서 수정된 엔티티를 find.
    2. 수정된 엔티티는 수정 쿼리를 만들어 쓰기지연 SQL 저장소에 등록
    3. 쓰기 지연 저장소의 쿼리를 데이터베이스에 전송
  • flush 발생 시점

    1. entityManager.flush() 직접 호출
    2. Transaction commit -> 자동 호출
    3. JPQL 쿼리 실행 -> 자동 호출
      • Transaction.begin 후 persist()를 한 Entity는 아직 1차 캐시에만 존재 -> DB에 적용 ❌
      • 중간에 JPQL 사용 시, 적용이 안된 Entity를 DB에 적용할 필요성 ⭕
      • 그래서 JPA는 해당 문제 해결을 위해 JPQL에서도 자동 Flush 호출
  • 플러시 모드 직접 지정 (javax.persistence.FlushModeType)

    • FlushModeType.AUTO -> 커밋이나 쿼리를 실행할 때 플러시(기본값)
    • FlushModeType.COMMIT -> 커밋할 때만 플러시

4.3 장점

4.3.1. 1차 캐시

  • 영속성 컨테스트가 가지고 있는 내부 캐시 (Key:Value 형식)
  • 영속 상태의 엔티티는 모두 이곳에 저장

  • 1차 캐시의 키는 Id
    -> 즉,식별자임 & 식별자 값은 DB PK와 Mapping 되있음
    -> 저장 & 조회의 모든 기준은 DB의 PK임!

4.3.2. 동일성 보장

4.3.3. Transaction을 지원하는 쓰기 지연

4.3.4. 변경 감지 (Dirty Checking)

4.3.5. 지연 로딩

5. CRUD로 알아보는 특징!

5.1. Read

  • 일련의 과정
    1. find() 호출
    2. 1차 캐시에서 식별자 값으로 Entity 탐색
    3. 있으면 해당 값 return
    4. 없다면 DB에서 조회해서 entity 생성
    5. 해당 entity를 1차 캐시에 저장 후 영속 상태의 entity 반환
Sample a = 
  entityManager.find(Sample.class, "1");
Sample b = 
  entityManager.find(Sample.class, "1");

System.out.println(a == b); // true or false?
  • 동일한 조건의 find()을 반복 호출해도 영속성 컨텍스트는 1차 캐시에 있는 같은 entityManager를 반환
    -> 즉, return true

성능상 이점과 entity의 동일성을 보장

5.2. Create

  • 엔티티 매니저는 Trasaction을 commit하기 직전까지 DB에 entity를 저장 ❌, 내부 쿼리 저장소에 SQL을 모아둠
  • Transaction commit하며 쿼리를 DB에 보냄
    -> 해당 과정이 Transaction을 지원하는 쓰기 지연


  • 일련의 과정

    1. persist()
    2. insert SQL 생성 & 1차 캐시에 저장
    3. app -> em : commit()
    4. em -> DB : flush
    5. em -> DB : commit
  • ex)

begin();

save(); // 1~3
save(); // 1~3
save(); // 1~3

commit(); // 4~5

등록 쿼리를 트랜잭션 커밋 시 일괄 전송 → 성능 최적화 가능!

5.3 Update

  • SQL을 통한 수정 작업의 문제점 (비즈니스 로직이 SQL에 의존!)
    1. 수정 쿼리가 많아짐
    2. 비즈니스 로직을 분석하기 위해 SQL을 주기적으로 확인해야 함
  • JPA에서는 Entity를 조회 후 필드만 변경하면 자동으로 update됨.
    -> Dirty Checking을 통해 가능!

  • 스냅샷
    • Entity를 영속성 컨텍스트에 보관 시, 최초 상태를 복사해서 저장.
    • flush 시점에 스냅샷과 현재 Entity 상태를 비교하여 변경사항을 감지함.
  • 오직, 영속성 컨텍스트가 관리하는 영속 상태의 엔티티만 적용
    • JPA 기본 전략으로 변경 사항이 있는 엔티티의 모든 필드를 Update
    • Hibernate의 @DynamicUpdate를 사용하면 수정된 필드만 업데이트 가능!

5.4 Delete

  • 일련의 과정
    1. remove()
    2. delete SQL 생성
    3. app -> em : commit()
    4. em -> DB : flush
    5. em -> DB : commit

6. 준영속

  • 영속성 컨텍스트가 관리하는 영속상태의 Entity가 영속성 컨텍스트에서 분리된 것
    -> 준영속 Entity는 영속성 컨테스트가 제공하는 기능 사용 ❌

6.1. 영속 -> 준영속

6.1.1. detach()

  • 특정 Entity를 준영속 상태로 만드는 Method

  • 영속성 컨텍스트에서 분리되면 변경 감지, 쓰기 지연, 1차 캐시 등 기능이 모두 비활성화됨

6.1.2. clear()

  • 영속성 컨텍스트를 초기화
    -> void 상태로 만듬, 모든 Entity를 준영속으로 만듬

6.1.3. close()

  • 영속성 컨텍스트 종료
    -> 완전 종료, 모든 Entity를 준영속으로 만듬

6.2. 준영속 특징

  1. 거의 비영속과 가까움
  2. 식별자를 가짐
  3. 지연 로딩 ❌

6.3 준영속 -> 영속

  • merge()로 준영속, 비영속 상태의 엔티티 데이터로 복사 후 새로운 영속 상태의 Entity를 반환

  • 병합과정

    1. Parameter로 넘어온 Entity의 식별자 값으로 영속성 컨텍스트 조회
    2. 있다면 넘어온 객체의 값을 복사한 영속 상태의 Entity를 return
    3. 없다면 DB에서 조회
    4. DB에 있다면 해당 객체 값을 복사한 영속 상태의 Entity를 return
    5. DB에도 없다면 새로운 엔티티를 생성해서 병합하고 return
profile
Backend Developer

0개의 댓글