1. 엔티티 매니저 팩토리와 엔티티 매니저
EntityManagerFactory는 애플리케이션 생성할 때 1번만 생성한다. 1개의 DB당 1개!
EntityManager는 쓰레드 간에 공유하지 말아야 한다. 고객의 요청 1회당 1번씩 생성된다.

2. 영속성 컨텍스트
엔티티를 영구 저장하는 환경이라는 의미
EntityManager.persist(entity);
DB에 저장하는 것이 아니라 엔티티를 영속성 컨텍스트 라는 곳에 저장한다는 의미
영속성 컨텍스트는 논리적인 개념으로 눈에 보이지 않는다.
엔티티 매니저를 통해서 영속성 컨텍스트에 접근한다.
고객의 요청이 들어오면 생성하고, 고객의 요청이 끝나면 사라짐(아래 영속성 컨텍스트의 이점에 있는 1차 캐시도 이때 다 사라지기 때문에 큰 성능 이점을 얻을 수는 없음)
3. 엔티티의 생명주기
1) 비영속(new/transient) : 영속성 컨텍스트와 전혀 관계가 없는 새로운 생성
-> 멤버 객체를 생성한 상태
2) 영속(managed) : 영속성 컨텍스트에 관리되는 상태
-> 객체를 생성하고, 객체를 저장한 상태 ex) entityManager.persist(member);
이때, DB에 데이터가 저장되지 않음. commit을 해야 저장이 되어짐.
//엔티티를 생성한 상태(비영속)
Member member = new Member();
member.setId(1L);
member.setUsername("memberA");
//엔티티를 영속
em.persist(member);
3) 준영속(detached) : 영속성 컨텍스트에 저장되었다가 분리된 상태
-> entityManager.detached(member);
영속성 컨텍스트에서 없앰
4) 삭제(removed) : 삭제된 상태
-> DB에서 데이터를 지움
4. 영속성 컨텍스트의 이점
- 1차 캐시
: find를 하면 바로 DB에서 데이터를 찾는게 아니라 1차 캐시에서 찾아서 조회를 먼저함.
1차 캐시에 없다면 DB 조회 후 1차 캐시에 저장하여 반환한다.
Member member = new Member();
member.setId(1L);
member.setUsername("memberA");
//1차 캐시에 저장됨
em.persist(member);
//1차 캐시에서 조회. 이 때 DB를 접근하지 않기 때문에 로그에 쿼리문이 발생하지 않는다.
Member findMember = em.find(Member.class, 1L);
- 동일성(identify) 보장
: 1차 캐시로 반복 가능한 읽기 등급(REPEATABLE READ)의 트랜잭션 격리 수준을 DB가 아닌 애플리케이션 차원에서 제공
Member a = em.find(Member.class, "member1");
Member b = em.find(Member.class, "member1");
System.out.println(a == b); //동일성 비교 true
- 트랜잭션을 지원하는 쓰기 지연(transactional write-behind)
: persist할 때 SQL을 DB에 보내지 않고 있다가, commit 하는 순간 SQL을 보낸다.
persist할 때 SQL을 SQL 쓰기 지연 저장소에 보관하고 있다가 commit하는 순간 보낸다.
transaction.commit()을 하면, flush로 영속성 컨텍스트의 변경 내용을 DB에 보내고 commit을 한다.(5번의 플러시 내용 참고)
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
//엔티티 매니저는 데이터 변경시 트랜잭션을 시작해야 한다.
transaction.begin(); // 트랜잭션 시작
em.persist(memberA);
em.persist(memberB);
//여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.
//커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
transaction.commit(); // 트랜잭션 커밋
- 변경 감지(Dirty Checking)
: 스냅샷을 찍어서 비교 후 변경이 되어있으면 UPDATE, DELETE를 한다.
- 지연 로딩(Lazy Loading)
5. 플러시란?
영속성 컨텍스트의 변경 내용을 DB에 반영한다.
영속성 컨텍스트를 비우지 않는다.
영속성 컨텍스트의 변경 내용을 DB에 동기화
트랜잭션이라는 작업 단위가 중요하다. 커밋 직전에만 동기화하면 된다.
플러시가 발생하면 무슨 일이 발생될까?
- 변경 감지(Dirty Checking)
- 수정된 엔티티 쓰기 지연 SQL 저장소에 등록
- 쓰기 지연 SQL 저장소의 쿼리를 DB에 전송
* (플러시가 발생한다고 해서 트랜잭션 커밋이 발생하는 것은 아님)
* 플러시가 발생한다고 해서 1차 캐시가 다 지워지는 것은 아님
영속성 컨텍스트를 플러시 하는 방법
entityManager.flush() - 개발자 직접 호출
트랜잭션 커밋 - 플러시 자동 호출
JPQL 쿼리 실행 - 플러시 자동 호출
플러시 모드 옵션(사용할 일이 거의 없음)
entityManager.setFlushMode(FlushModeType.COMMIT)
- FlushModeType.AUTO(기본값) : 커밋이나 쿼리를 실행할 때 플러시
- FlushModeType.COMMIT : 커밋할 때만 플러시, 쿼리를 실행할 때는 플러시 하지 않음
6. 준영속 상태
영속에서 준영속으로 갈 수 있는 상태는
1) persist를 하거나,
2) find를 해서 가져올 때 영속성 컨텍스트에 없으면 DB에서 찾아서 1차 캐시에 올려놓는 것(영속성 컨텍스트에 올려놓는 것)
영속 상태의 엔티티가 영속성 컨텍스트에서 분리(detached)되는 것으로 영속성 컨텍스트가 제공하는 기능을 사용하지 못한다.
준영속 상태로 만드는 방법
entityManager.detach(entity)
특정 엔티티만 준영속 상태로 전환
entityManager.clear()
영속성 컨텍스트를 완전히 초기화
entityManager.close()
영속성 컨텍스트를 종료
'TIL > JPA' 카테고리의 다른 글
[TIL/JPA] 기본개념 : 프록시와 연관관계 관리[즉시(EAGER)로딩, 지연(LAZY)로딩] (0) | 2024.08.27 |
---|---|
[TIL/JPA] 기본개념 : 고급 매핑(상속관계 매핑, @MappedSuperclass) (0) | 2024.08.24 |
[TIL/JPA] 기본 개념 : 다양한 연관관계 매핑 (0) | 2024.08.22 |
[TIL/JPA] 기본 개념 : 연관관계 매핑 기초 (0) | 2024.08.17 |
[TIL/JPA] 기본 개념 : 엔티티 매핑 (0) | 2024.08.12 |