일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 제태크
- 기업분석
- 그리디 알고리즘
- S&P500
- 주식
- mco
- 금리인하
- 무디스
- StringBuffer
- Java
- 알고리즘
- 다형성
- 잉여현금흐름
- 주린이
- etf
- object
- XLF
- 배당성장
- javascript
- 미국주식
- 프로그래머스
- 인플레이션
- 자바
- 백준
- 금리인상
- FCF
- 접근제어자
- 객체지향
- 현금흐름표
- 오버라이딩
- Today
- Total
오늘의하루
JPA의 영속성 관리 본문
EntityManagerFactory와 EntityManager
EntityManagerFactory는 웹 애플리케이션에서 단 하나만 존재하며 EntityManager 객체를 생성할 수 있다.
영속성 컨텍스트
영속성 컨텍스트는 EntityManager를 통해서 접근이 가능하다.
처음 JPA를 접하는 경우 EntityManager와 PersistenceContext는 1:1 관계로 생각해야한다.
Entity의 생명주기
1. 비영속 (new) : PersistenceContext와 전혀 관계없는 새로운 상태
Member member = new Member();
member.setId(1L);
member.setName("JPA");
2. 영속 (managed) : PersistenceContext에서 관리되고 있는 상태
Member member = new Member();
member.setId(1L);
member.setName("JPA");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin(); // 트랜잭션 시작
em.persist(member); // 영속 상태
3. 준영속 (detached) : 영속 상태에서 분리(제거)된 상태
Member member = new Member();
member.setId(1L);
member.setName("JPA");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin(); // 트랜잭션 시작
em.persist(member); // 영속 상태
em.detach(member); // 준영속 상태 : 특정 엔티티만 준영속 상태로 전환
// em.clear(); // PersistenceContext를 완전히 초기화
4. 삭제 (remove) : 삭제된 상태
em.remove(member);
PersistenceContext의 이점
1. 1차 캐시
2. 동일성 보장
3. 트랙잭션을 지원하는 쓰기 지연
4. 변경 감지
5. 지연 로딩
1차 캐시
PersistenceContext 안에는 1차 캐시라는 공간이 있다.
Member member = new Member();
member.setId(1L);
member.setName("JPA");
// 영속 상태
em.persist(member);
이렇게 영속 상태가 되면 key는 @id 어노테이션이 붙은 컬럼이되고 Entity는 member 객체가 된다.
Member member = new Member();
member.setId(1L);
member.setName("JPA");
// 영속 상태
em.persist(member);
// DB에 접근하지 않고 1차 캐시에서 조회한다.
Member findMember = em.find(Member.class, 1L);
1차 캐시를 이용함으로써 DB에 접근하지 않고 조회할 수 있게 된다.
만약 1차 캐시에 없다면?
당연하겠지만 1차 캐시에 없다면 DB에 접근하여 조회해 온다.
하지만 이때 DB에서 조회해온 결과를 1차 캐시에 저장한 후 값을 반환하기 때문에 이 다음 작업부터는 캐시에 있는 Entity를 DB에 접근하지 않고도 사용이 가능하다.
동일성 보장
1차 캐시로 반복 가능한 읽기 등급의 트랜잭션 격리 수준을 데이터 베이스가 아닌 애플리케이션 차원에서 제공한다.
Member a = em.find(Member.class, 1L);
Member b = em.find(Member.class, 1L);
System.out.println(a == b); // 동일성 비교 결과 : true
쓰기 지연
EntityManager.persist()는 데이터베이스에 직접적으로 쿼리를 보내지 않는다.
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(memberA);
em.persist(memberB);
em.getTransaction().commit();
persist()를 호출하면 PersistenceContext의 1차 캐시에 저장하면서 동시에 Insert SQL문을 생성하여 쓰기 지연 SQL 저장소라는 공간에 순차적으로 쌓아두게 된다.
그 후 commit()을 호출하면 flush()가 호출되게 되고 flush함수를 통해 쓰기 지연 SQL 저장소에 쌓인 쿼리가 DB에 전송되고 commit()이 어루어 진다.
변경 감지
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Member findMember = em.find(Member.class, 1L);
findMember.setName("UpdateJPA");
em.getTransaction().commit();
이 코드는 해석해보면
1. 1차 캐시에 아무것도 없기 때문에 DB를 통해 @id에 해당하는 컬럼이 1인 결과를 찾는다.
2. 해당 결과를 1차 캐시에 저장하는데 Entity와 스냅샷(최초)이라는 곳에 저장된다.
3. setName 함수 호출되며 1차 캐시의 Entity가 변경된다.
4. commit 함수 호출 현재 flush 함수 호출
5. 2번에서 최초에 저장된 스냅샷과 지금의 Entity를 비교한다. [더티 체킹]
7. 변경이 있다면 Update SQL문을 생성하여 쓰기 지연 SQL 저장소에 저장한다.
- 쓰기 지연 SQL 저장소는 등록, 수정, 삭제 쿼리가 저장된다.
8. DB에 쿼리를 날린 후 commit한다.
Flush 관련 내용
flush를 하면 쓰기 지연 SQL 저장소에 쌓인걸 DB에 보내주는 역할을 한다.
이는 PersistenceContext를 비우는 기능이 아니라 변경 내용을 DB에 동기화 시키는 작업이다.
PersistenceContext를 Flush하는 방법
1. em.flush() : 직접 flush 호출
2. tx.commit() : flush 자동 호출
3. JPQL 쿼리 실행 : flush 자동 호출
'Spring > JPA' 카테고리의 다른 글
JPA 연관 관계 매핑 - start (1) | 2024.01.14 |
---|---|
JPA 기본키 매핑 (1) | 2024.01.12 |
JPA 엔티티 매핑 (0) | 2024.01.02 |
JPA에서 batch_size를 지정하는 이유는? (0) | 2024.01.02 |
JPA의 의미 및 기본 사용 방법 (1) | 2023.12.31 |