[자바 ORM 표준 JPA 프로그래밍] 3. 영속성 관리
2022. 5. 13. 01:51ㆍWeb/Spring
반응형
date: 2022-03-10T13:57:15.537Z
김영한님의 '자바 ORM 표준 JPA 프로그래밍' 서적을 읽고 정리한 글 입니다.
엔티티 매니저 팩토리와 엔티티 매니저
엔티티 매니저 팩토리
- 엔티티 매니저를 만드는 공장.
- 한 개만 만들어서 애플리케이션 전체에서 공유하도록 설계됨. (생성 비용이 큼)
- 여러 스레드가 동시에 접근해도 안전
엔티티 매니저
emf.createEntityManager()
을 통해 생성.- 생성 비용이 거의 들지 않는다.
- 여러 스레드가 동시에 접근하면 동시성 문제 발생.
- 데이터베이스 연결이 꼭 필요한 시점까지 커넥션을 얻지 않는다.
영속성 컨텍스트
- 엔티티를 영구 저장하는 환경.
em.persist(entity)
는 엔티티 매니저를 사용해서 엔티티를 영속성 컨텍스트에 저장하는 것이다.- 엔티티 매니저를 통해서 영속성 컨텍스트에 접근할 수 있고 영속성 컨텍스트를 관리할 수 있다.
엔티티의 생명주기
- 비영속(new/transient): 영속성 컨텍스트와 전혀 관계 없는 새로운 상태
- 영속(managed): 영속성 컨텍스트에 관리되는 상태
- 준영속(detached): 영속성 컨텍스트에 저장되었다가 분리된 상태
- 삭제(removed): 삭제된 상태
비영속
- member 객체를 생성만 하고 엔티티 매니저에 아무것도 안 넣은 상태다.
- JPA와 전혀 관계없는 상태라고 할 수 있다.
영속
em.persist()
로 객체를 넣어주면, 엔티티 매니저 안에 있는 영속성 컨텍스트에 엔티티가 들어가면서 영속 상태가 된다.- 영속 상태라는 것은 영속성 컨텍스트에 의해 관리된다는 뜻이다.
준영속
- 영속 상태의 엔티티를 영속성 컨텍스트가 관리하지 않게되면 준영속 상태가 된다.
em.detach()
,em.close()
,em.clear()
를 호출하면 준영속 상태가 된다.
삭제
- 엔티티를 영속성 컨텍스트와 데이터베이스에서 삭제한다.
em.remove()
영속성 컨텍스트의 장점
1차 캐시
- 영속화를 하면
@Id
로 매핑한 식별자를 키로, 엔티티 객체가 값이 되어 1차 캐시에 저장된다. - 엔티티를 조회할 때 1차 캐시에 있으면 그 데이터를 반환하고, 없다면 DB에서 조회한 후 1차 캐시에 저장한 후에 영속 상태의 엔티티를 반환한다.
동일성 보장
Member a = em.find(Member.class, "member1");
Member b = em.find(Member.class, "member1");
System.out.println(a == b); // true
- 동일한 엔티티를 반복해서 호출해도 영속성 컨텍스트는 1차 캐시에 있는 같은 엔티티 인스턴스를 반환한다.
트랜잭션을 지원하는 쓰기 지연
- 엔티티 매니저는 트랜잭션을 커밋하기 직전까지 내부 쿼리 저장소에 쿼리를 차곡차곡 모아둔다.
- 트랜잭션을 커밋할 때 모아둔 쿼리를 DB에 보낸다.
- 이 기능을 잘 활용하면 모아둔 등록 쿼리를 DB에 한 번에 전달해서 성능을 최적화 할 수 있다.
변경 감지
SQL 수정 쿼리의 문제점
- 수정 쿼리 개수가 많아진다.
- 비즈니스 로직을 분석하기 위해 SQL을 계속 확인해야 한다. (비즈니스 로직이 SQL에 의존하게 된다)
JPA 변경 감지
- 엔티티의 변경사항을 DB에 자동으로 반영하는 기능 (Dirty Checking)
- 엔티티를 영속성 컨텍스트에 보관할 때, 최초 상태를 복사해서 저장해둔다. (스냅샷)
- flush 시점에 스냅샷과 엔티티를 비교해서 변경된 엔티티를 찾는다.
- 변경 감지는 영속 상태의 엔티티에만 적용된다.
- JPA의 기본 전략은 엔티티의 모든 필드를 업데이트한다. (
@DynamicUpdate
으로 수정된 데이터만 동적으로 업데이트 할 수 있음.)- 애플리케이션 로딩 시점에 수전 쿼리를 미리 생성해두고 재사용 할 수 있다.
- DB에 동일한 쿼리를 보내면 DB는 이전에 파싱된 쿼리를 재사용할 수 있다.
상황에 따라 다르지만 칼럼이 대략 30개 이상이 되면
@DynamicUpdate
를 사용한 동적 수정 쿼리가 더 빠르다고 한다.
플러시
영속성 컨텍스트의 변경 내용을 DB에 반영한다.
영속성 컨텍스트를 플러시하는 방법
- 직접 호출
- 트랜잭션 커밋
- JPQL 쿼리 실행 (JPQL을 중간에 실행했는데 아직 커밋을 하지 않아서
persist()
한 내용을 불러올 수 없으면 문제가 생길 수 있다. 그래서 JPQL 실행 시에는 자동으로 무조건flush()
를 날려버린다.)
플러시 모드 옵션
FlushModeType.AUTO
- 기본값
- 커밋이나 쿼리를 실행할 때 플러시 된다.
FlushModeType.COMMIT
- 커밋할 때만 플러시 된다.
- 중간에 실행하는 JPQL 쿼리가 앞과는 전혀 다른 데이터를 써서 굳이 당장 플러시할 필요가 없을 때 사용하면 된다.
준영속
영속 상태의 엔티티가 영속성 컨텍스트에서 분리된 상태.
준영속 상태로 만드는 방법
em.detach()
em.clear()
em.close()
준영속 상태의 특징
- 거의 비영속 상태에 가깝다. (영속성 컨텍스트가 제공하는 어떠한 기능도 동작하지 않는다)
- 식별자 값을 가지고 있다.
- 지연 로딩을 할 수 없다.
반응형