JPA에서 가장 중요한 것
- 객체와 관계형 데이터베이스 매핑하기
- 영속성 컨텍스트
개념
엔티티 매니저 팩토리와 엔티티 매니저

영속성 컨텍스트
- 엔티티를 영구 저장하는 환경 
- EntityManager.persist(entity)- persist는 DB에 저장하는것이 아니라 영속성 컨텍스트에 저장한다는 의미이다 
- 영속성 컨텍스트는 논리적인 개념 
- 엔티티 매니저를 통해서 영속성 컨텍스트에 접근함 
엔티티의 생명주기

- 비영속 (new/transient) 
 영속성 컨텍스트와 전혀 관계가 없는 새로운 상태
- 영속 (managed) 
 영속성 컨텍스트에 관리되는 상태
- 준영속 (detached) 
 영속성 컨텍스트에 저장되었다가 분리된 상태
- 삭제 (removed) 
 삭제된 상태
비영속
- 현재 JPA랑 관계없음

영속
- 객체를 저장한 상태
- 영속성 컨텍스트에 저장하지만 DB쿼리는 없음
- Transaction commit 해야만 DB에 쿼리 날림
- persist(),find() 를 할때도 영속 컨텍스트에 없엇다면, 생김

준영속
- 회원 엔티티를 영속성 컨텍스트에서 분리, 준영속 상태
- em.detach(member);
삭제
- 객체를 삭제한 상태(삭제)
- DB에서 해당 객체의 데이터 삭제 요청
- em.remove(member)
영속성 컨텍스트의 이점
- 1차 캐시
- 동일성(identity) 보장
- 트랜잭션을 지원하는 쓰기 지연 (transactional write-behind)
- 변경 감지(Dirty Checking)
- 지연 로딩(Lazy Loading)
1차 캐시
- DB 트랜잭션 단위로 영속 컨텍스트가 존재함(트랜잭션 끝나면 삭제됨)
- 따라서 큰 효과는없음

동일성
- 한 트랜잭션에서 같은 객체 find시 객체 참조값 같음. Equal

쓰기 지연
- commit 이전까지 계속 영속 컨텍스트에만 쌓아둠
- SQL문은 쓰기 지연 SQL 저장소에 쌓아둠 (trancsaction.commit시 DB에 쿼리 날림)
- Hibernate의 batch_size기능을 활용하여, SQL문을 한번에 보낼수있다.
| 1 | EntityManager em = emf.createEntityManager(); | 

변경 감지 (더티 체킹)
- 한 트랜잭션 안에서 변경사항 발생시 자동으로 DB에 마지막 쿼리로 update함
- Transaction.commit() 시에 영속 컨텍스트의 스냅샷(읽은 최소 객체 상태 기억)과 비교하여 다른점을 update함
| 1 | EntityManager em = emf.createEntityManager(); | 

제거(엔티티 삭제)
- commit 시점에 delete쿼리 나감
| 1 | //삭제 대상 엔티티 조회 | 
플러시(flush)
영속성 컨텍스트의 변경내용을 데이터베이스에 반영
(1차 캐시는 지워지지않는다. 트랜잭션이 끝나지 않았기 때문이다.)
동작
- 변경 감지
- 수정된 엔티티 쓰기 지연 SQL 저장소에 등록
- 쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송 (등록, 수정, 삭제 쿼리)
- 앞에 1,2번 진행후 DB에 쿼리 박히는 3번 진행함
영속성 컨텍스트를 플러쉬하는 방법
- em.flush() - 직접 호출
- 트랜잭션 커밋 - 플러시 자동 호출
- JPQL 쿼리 실행 - 플러시 자동 호출
 (em.createQuery(“[JPQL문]”)=>발생시 이때 DB에 이전 쿼리 반영하고난후 JPQL 동작 호출됨)
플러쉬 요약
- 영속성 컨텍스트를 비우지 않음
- 영속성 컨텍스트의 변경내용을 데이터베이스에 동기화
- 트랜잭션이라는 작업 단위가 중요 -> 커밋 직전에만 동기화 하면 됨
준영속 상태
- 영속 -> 준영속
- 영속 상태의 엔티티가 영속성 컨텍스트에서 분리(deteched)
- 영속성 컨텍스트가 제공하는 기능을 사용 못함(더티 체킹 등등)
준영속 상태 만드는 법
- em.detach(entity)
 특정 엔티티만 준영속 상태로 전환
- em.clear()
 영속성 컨텍스트를 완전히 초기화
- em.close()
 영속성 컨텍스트를 종료
JPA의 commit과 flush는 다르다.
- 트랜잭션을 begin()으로 시작한 뒤commit()하여 트랜잭션을 종료해야한다.
- commit()을 수행하게 되면 내부적으로 EntityManager의- flush()메서드를 호출한 후 트랜잭션을 닫습니다
- flush는 쿼리를 전송하는 역할이고, commit은 내부적으로 flush를 수행한뒤 트랜잭션을 끝내는 역할입니다
- 따라서, flush 로 전송된 쿼리는 rollback할 수 있다.(트랙잭션 중이므로), 하지만 commit은 트랜잭션을 끝내므로 rollback 할수없다.