Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
Tags
- Be
- 백준
- 오블완
- Java
- 백엔드 부트캠프
- 내일배움카드
- baekjoon
- 환급챌린지
- 국비지원교육
- 오픈챌린지
- 자바
- 티스토리챌린지
- UXUI기초정복
- 디자인강의
- 오픈패스
- 내일배움캠프
- KDT
- 디자인교육
- mysql
- UXUI챌린지
- 국비지원
- 백엔드개발자
- 국비지원취업
- UXUIPrimary
- OPENPATH
- 부트캠프
- 객체지향
- 디자인챌린지
- Spring
- 패스트캠퍼스
Archives
- Today
- Total
군만두의 IT 공부 일지
[스터디10] 03. 영속성 관리 본문
목차
3장. 영속성 관리
3.1 엔티티 매니저 팩토리와 엔티티 매니저
- 데이터베이스를 하나만 사용하는 애플리케이션은 일반적으로 EntityManagerFactory를 하나만 생성한다.
- 엔티티 매니저 팩토리는 여러 스레드가 동시에 접근해도 안전하므로 서로 다른 스레드 간 공유해도 되지만, 엔티티 매니저는 여러 스레드가 동시에 접근하면 동시성 문제가 발생하므로 스레드 간에 절대 공유하면 안 된다.
// 엔티티 매니저 팩토리 생성, 비용이 아주 많이 든다.
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("jpabook");
// 엔티티 매니저 생성, 비용이 거의 안 든다.
EntityManager em = emf.createEntityManager();
3.2 영속성 컨텍스트란?
- 영속성 컨텍스트(persistence context): 엔티티를 영구 저장하는 환경
- 엔티티 매니저로 엔티티를 저장하거나 조회하면 엔티티 매니저는 영속성 컨텍스트에 엔티티를 보관하고 관리한다.
- persist() 메소드는 엔티티 매니저를 사용해서 엔티티를 영속성 컨텍스트에 저장한다.
- 영속성 컨텍스트는 엔티티 매니저를 생성할 때 만들어지고, 엔티티 매니저를 통해 접근 및 관리할 수 있다.
3.3 엔티티의 생명주기
엔티티에는 4가지 상태가 있다.
- 비영속(new/transient): 영속성 컨텍스트와 전혀 관계가 없는 상태
- 영속(managed): 영속성 컨텍스트에 저장된 상태
- 준영속(detached): 영속성 컨텍스트에 저장되었다가 분리된 상태
- 삭제(removed): 삭제된 상태
// 비영속 상태
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
// 영속 상태
em.persist(member);
// 준영속 상태
em.detach(member);
// 삭제 상태
em.remove(member);
3.4 영속성 컨텍스트의 특징
- 영속성 컨텍스트와 식별자 값: 영속성 컨텍스트는 엔티티를 식별자 값으로 구분한다. 영속 상태는 식별자 값이 반드시 있어야 한다. (없으면 예외 발생)
- 영속성 컨텍스트와 데이터베이스 저장: JPA는 보통 트랜잭션을 커밋하는 순간 영속성 컨텍스트에 새로 저장된 엔티티를 데이터베이스에 반영한다. (플러시, flush)
- 영속성 컨텍스트가 엔티티를 관리할 때 장점
- 1차 캐시
- 동일성 보장
- 트랜잭션을 지원하는 쓰기 지연
- 변경 감지
- 지연 로딩
3.4.1 엔티티 조회
- 1차 캐시: 영속성 컨텍스트가 내부에 가지고 있는 캐시. 영속 상태의 엔티티는 모두 이곳에 저장된다.
- 1차 캐시의 키는 식별자 값이고 식별자 값은 데이터베이스 기본키와 매핑되어 있으므로, 영속성 컨텍스트에 데이터를 저장/조회하는 모든 기준은 데이터베이스 기본키 값이다.
- 영속성 컨텍스트는 성능상 이점과 엔티티의 동일성(identity, ==)을 보장한다.
// 1차 캐시에서 조회
Member a = em.find(Member.class, "member1"); // DB 조회 후 1차 캐시 저장
Member b = em.find(Member.class, "member1"); // 1차 캐시에서 조회
System.out.println(a == b); // true (동일성 보장)
3.4.2 엔티티 등록
- 트랜잭션을 지원하는 쓰기 지연(transactional write-behind): 엔티티 매니저가 트랜잭션을 커밋하기 직전까지 데이터베이스에 엔티티를 저장하지 않고 내부 쿼리 저장소에 등록 쿼리를 모았다가, 트랜잭션을 커밋할 때 모아둔 등록 쿼리를 데이터베이스에 보내는 것
- 트랜잭션을 지원하는 쓰기 지연이 가능한 이유: 어떻게든 커밋 직전에만 데이터베이스에 SQL을 전달하면 되기 때문이다.
3.4.3 엔티티 수정
- SQL 수정 쿼리의 문제점: SQL을 사용하면 수정 쿼리를 직접 작성해야 한다. 요구사항이 늘어나면서 수정 쿼리가 많아지는 것은 물론이고, 비즈니스 로직을 분석하기 위해 SQL을 계속 확인해야 한다. 직간접적으로 비즈니스 로직이 SQL에 의존하게 된다.
- 변경 감지(dirty checking): 엔티티의 변경사항을 데이터베이스에 자동으로 반영하는 기능. 영속성 컨텍스트가 관리하는 영속 상태의 엔티티에만 적용된다. (비영속, 준영속은 반영X)
- 스냅샷: JPA가 엔티티를 영속성 컨텍스트에 보관할 때, 최초 상태를 저장해서 저장해두는 것
- JPA의 기본 전략은 엔티티의 모든 필드를 업데이트한다.
- 장점: 모든 필드를 사용하면 수정 쿼리가 항상 같다. 쿼리를 재사용할 수 있다.
- 단점: 데이터베이스에 보내는 데이터 전송량이 증가한다.
- 상황에 따라 컬럼이 많으면 기본 방법인 정적 수정 쿼리보다 @DynamicUpdate를 사용한 동적 수정 쿼리가 빠르다. 하지만 한 테이블에 컬럼이 많다는 것은 테이블 설계상 책임이 적절히 분리되지 않았을 가능성이 높다.
3.4.4 엔티티 삭제
- remove()에 삭제 대상 엔티티를 넘겨주면 엔티티 등록과 비슷하게 삭제 쿼리를 쓰기 지연 SQL 저장소에 등록한다. 이후 트랜잭션을 커밋해서 플러시를 호출하면 실제 데이터베이스에 삭제 쿼리를 전달한다.
- remove()를 호출하는 순간 영속성 컨텍스트에서 제거된다. 삭제된 엔티티는 재사용하지 말고 자연스럽게 가비지 컬렉션의 대상이 되도록 두는 것이 좋다.
3.5 플러시
- 플러시(flush()): 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영한다.
- 영속성 컨텍스트를 플러시하는 방법
- em.flush()를 직접 호출한다. → 거의 사용하지 않는다.
- 트랜잭션 커밋 시 플러시가 자동 호출된다.
- JPQL 쿼리 실행 시 플러시가 자동 호출된다.
- 식별자를 기준으로 조회하는 find() 메소드를 호출할 때는 플러시가 실행되지 않는다.
3.5.1 플러시 모드 옵션
엔티티 매니저에 플러시 모드를 직접 지정하려면 javax.persistence.FlushModeType(현재는 jakarta.persistence.FlushModeType)을 사용한다.
- FlushModeType.AUTO: 커밋이나 쿼리를 실행할 때 플러시(기본값)
- FlushModeType.COMMIT: 커밋할 때만 플러시
3.6 준영속
- 준영속 상태: 영속성 컨텍스트가 관리하는 영속 상태의 엔티티가 영속성 컨텍스트에서 분리된(detached) 것
- 준영속 상태의 엔티티는 영속성 컨텍스트가 제공하는 기능을 사용할 수 없다.
- 영속 상태의 엔티티를 준영속 상태로 만드는 방법
- em.detach(entity): 특정 엔티티만 준영속 상태로 전환한다.
- em.clear(): 영속성 컨텍스트를 완전히 초기화한다.
- em.close(): 영속성 컨텍스트를 종료한다.
3.6.4 준영속 상태의 특징
준영속 상태인 엔티티는 다음과 같다.
- 거의 비영속 상태에 가깝다. (즉, 영속성 컨텍스트가 제공하는 어떠한 기능도 동작하지 않는다)
- (영속 상태였으므로) 식별자 값을 가지고 있다.
- 지연 로딩(실제 객체 대신 프록시 객체를 로딩해두고 해당 객체를 실제 사용할 때 영속성 컨텍스트를 통해 데이터를 불러오는 방법)을 할 수 없다.
3.6.5 병합: merge()
- 준영속 상태의 엔티티를 다시 영속 상태로 변경하려면 병합을 사용한다. 병합은 비영속 엔티티도 영속 상태로 만들 수 있다.
- merge() 메소드는 준영속 상태의 엔티티를 받아서 새로운 영속 상태의 엔티티를 반환한다.
- 식별자 값으로 엔티티를 조회할 수 있으면 불러서 병합하고 조회할 수 없으면 새로 생성해서 병합한다. (save or update)
✔️ 복습하기
- 영속성 컨텍스트란?
- 플러시란?
- 더티 체킹이란?
이 글은 『 자바 ORM 표준 JPA 프로그래밍』 책을 학습한 내용을 정리한 것입니다.
'프로그래밍 > Java' 카테고리의 다른 글
[스터디10] 05. 연관관계 매핑 기초 (0) | 2025.07.19 |
---|---|
[스터디10] 04. 엔티티 매핑 (0) | 2025.07.10 |
[스터디10] 02. JPA 시작 (0) | 2025.07.03 |
[스터디10] 01. JPA 소개 (0) | 2025.06.28 |
[스터디7] 09. 아키텍처 방식 및 XML, HTTP, JSON (0) | 2025.06.19 |
Comments