JPA에서 가장 중요한 2가지는 객체와 관계형 데이터베이스 매핑하기와 영속성 컨텍스트 라고 한다.

저번 시간에 실습을 하면서 배운 엔티티 매니저 팩토리와 엔티티 매니저와의 관계이다. 요청이 들어올 때마다 entityManager가 생성이 되고 커넥션을 사용하게 되면 DB와 연결되는 형식이다.
영속성 컨텍스트
영속성 컨텍스트는 JPA를 이해하는데 가장 중요한 용어이다. 쉽게 말해 엔티티를 영구 저장하는 환경이라는 뜻이다.
EntityManager.persist(entity);를 할 경우 entity를 영속성 컨텍스트에 저장한다는 뜻이다.
영속성 컨텐스트는 논리적인 개념이고 눈에 보이지 않는다. 그리고 엔티티 매니저를 통해서 영속성 컨텍스트에 접근하게 된다.
엔티티의 생명주기

- 비영속(new/transient) : 영속성 컨텍스트와 전혀 관계가 없는 새로운 상태이다.
- 영속(managed) : 영속성 컨텍스트에 관리 되는 상태이다. 즉 persist를 한 경우이다.
- 준영속(detached) : 영속성 컨텍스트에 저장되었다가 분리된 상태이다.
- 삭제(removed) : 삭제된 상태이다.
1. 비영속
비영속은 member객체를 생성하고 영속 컨텍스트(entitiyManager)에 저장을 안 한 경우이다.
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
2. 영속
persist를 해 영속 컨텍스트에 member를 집어넣은 경우이다.
//객체를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUsername(“회원1”);
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
//객체를 저장한 상태(영속)
em.persist(member);
이때는 아직 DB에 저장이 안 된다. commit을 한 시점부터 DB에 퀴리가 날라간다.
3. 준영속, 삭제
//회원 엔티티를 영속성 컨텍스트에서 분리, 준영속 상태
em.detach(member);
//객체를 삭제한 상태(삭제)
em.remove(member);
영속성 컨텍스트의 이점
1. 엔티티 조회, 1차 캐시
영속성 컨텍스트 안에는 1차 캐시가 존재한다.

1차 캐시 모습은 이렇게 생겼다. @id 는 Member 클레스에서 징해준 id이다. Entity는 em.persist(member)를 할 때 member가 저장된다.
이럴 경우 조회에서 이점이 존재한다. em.find(Memeber.class, "member1");을 할 경우 DB부터 검색하는 것이 아닌 1차 캐시부터 찾는다. 1차 캐시에 존재할 경우 바로 리턴한다.
만약 1차 캐시안에 존재하지 않는 다면 DB를 조회하고 1차 캐시에 저장후에 반환한다.
=> 그렇게 큰 이점은 얻을 수가 없다. 왜냐하면 영속 컨텍스트는 고객이 요청 할 때 만들고 요청이 종료한 후에는 사라지게 된다. 그러므로 1차 캐시도 사라지게 된다.
2. 영속 엔티티의 동일성 보장
Member a = em.find(Member.class, "member1");
Member b = em.find(Member.class, "member1");
System.out.println(a == b); //동일성 비교 true
1차 캐시로 반복 가능한 읽기(REPEATABLE READ) 등급의 트랜잭션 격리 수준을 데이터베이스가 아닌 애플리케이션 차원에서 제공한다. 같은 트랜잭션 안에서 같다.
3.엔티티 등록, 트랜잭션을 지원하는 쓰기 지연
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
//엔티티 매니저는 데이터 변경시 트랜잭션을 시작해야 한다.
transaction.begin(); // [트랜잭션] 시작
em.persist(memberA);
em.persist(memberB);
//여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.
//커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
transaction.commit(); // [트랜잭션] 커밋
위 코드가 트랜잭션이 흘러가는 과정이다.
em.persist(memberA)를 할 경우 insert SQL을 생성해 쓰기 지연 SQL 저장소에 저장한다. 동시에 1차 캐시에도 저장한다.
em.persist(memberB)를 할 경우 insert SQL을 생성해 쓰기 지연 SQL 저장소에 저장한다. 동시에 1차 캐시에도 저장한다.
그 후 transaction.comit(); 을 한 순간 DB에 넘어가게 된다.
4.엔티티 수정, 변경 감지
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin(); // [트랜잭션] 시작
// 영속 엔티티 조회
Member memberA = em.find(Member.class, "memberA");
// 영속 엔티티 데이터 수정
memberA.setUsername("hi");
memberA.setAge(10);
transaction.commit(); // [트랜잭션] 커밋
이렇게 set만 설정해도 신기하게 테이블에 내용이 변경이 된다.

왼쪽의 그림은 변경이 일어 났을 경우 JPA가 흘러가는 모습을 보여주는 것이다. 1차 캐시안에는 스냅샷이 존재한다. 스냅샷은 제일처음 저장했을때의 데이터가 들어가 있다. memberA를 변경할 경우 스냅샷과 비교한 뒤 Update SQL을 생성하고 쓰기 지연 SQL 저장소에 저장한다. 그 후 DB에 보낸후 commit한다.
5. 엔티티 삭제
//삭제 대상 엔티티 조회
Member memberA = em.find(Member.class, “memberA");
em.remove(memberA); //엔티티 삭제
플러시
영속성 컨텍스트의 변경내용을 데이베이스에 반영한다.
플러시 발생 순서
- 변경 감지
- 수정된 엔티티 쓰기 지연 SQL 저장소에 등록
- 쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송(등록, 수정, 삭제 쿼리)
영속성 컨텍스트를 플러시하는 방법
- em.flush() : 직접 호출, comit 하기전에 먼저 flush하기 위해서
- 트랜잭션 커밋 : 플러시 자동 호출
- JPQL 쿼리 실행 : 플러시 자동 호출, 중간에 JPQL을 실행하면 위에 comit하기전 persist한 내용이 조회가 안될 수 있으므로 프러시가 자동 실행 된다.
플러시 모드 옵션
em.setFlushMode(FlushModeType.COMMIT)와 같이 사용한다.
- FlushModeType.AUTO : 커밋이나 쿼리를 실행할 때 플러시 (기본값)
- FlushModeType.COMMIT : 커밋할 때만 플러시
플러쉬를 할경우 1차 캐쉬가 사라지는게 아니다. 플러쉬는 쓰기 지연 SQL 저장소에 있는 쿼리를 그냥 DB에 보내는 것이다.
트랜잭션이라는 작업 단위가 중요하다. 커밋 직전에만 동기화 하면 된다.
준영속 상태
영속 상태의 엔티티가 영속성 컨텍스테에서 분리 된 경우이다. (detached)
영속성 컨텍스트가 제공하는 기능을 사용하지 못하게 된다.
준영속 상태로 만드는 방법
- em.detach(entity) : 특정 엔티티만 준영속 상태로 전환
- em.clear() : 영속성 컨텍스트를 완전히 초기화
- em.close() : 영속성 컨텍스트를 종료
강의 출처 : https://www.inflearn.com/course/ORM-JPA-Basic
자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런 | 강의
JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다., - 강의 소개 | 인프런
www.inflearn.com
'BackEnd > 자바 ORM 표준 JPA 프로그래밍' 카테고리의 다른 글
JPA 엔티티 매핑(필드와 컬럼 매핑, 기본 키 매핑) (1) | 2022.12.22 |
---|---|
JPA 엔티티 매핑(객체와 테이블 매핑) (0) | 2022.12.22 |
JPA 시작 (1) | 2022.12.22 |
JPA 소개(자바 ORM 표준 JPA 프로그래밍 - 기본편) (0) | 2022.12.21 |
JPA 소개(자바 ORM 표준 JPA 프로그래밍 - 기본편) (0) | 2022.12.20 |