다크 모드를 권장합니다
영속성 관리
EntityManagerFactory와 EntityManager
- 엔티티 매니저는 엔티티 CRUD와 관련된 모든 일을 처리한다.
- 엔티티 매니저 팩토리에서 엔티티 매니저를 생성한다.
- 엔티티매니저는 데이터베이스 연결이 필요할 때(예: 트랜잭션 시작)마다 커넥션풀에서 커넥션을 획득한다.
엔티티의 생명주기
- 영속성 컨텍스트 : 엔티티를 영구 저장하는 환경
- 엔티티 매니저로 엔티티를 저장/조회하면 엔티티 매니저는 영속성 컨텍스트에 엔티티를 보관
- 이때 “엔티티를 저장”한다는 것
- DB에 곧바로 저장한다 (x)
- 영속성 컨텍스트에 보관한다(o)
- 영속성 컨텍스트는 논리적인 개념에 가깝다.
영속성 컨텍스트의 상태
4가지 상태가 존재한다.
- 비영속 (new/transient)
: 영속성 컨텍스트와 무관한 상태. 엔티티를 생성하고 아직 저장하지 않았을 경우 비영속에 해당됨.
- 영속(managed)
: 엔티티 매니저를 통해 엔티티를 영속성 컨텍스트에 저장한 상태. 영속성 컨텍스트에 의해 관리되는 상태.
- 준영속(detached)
: 영속성 컨텍스트에 의해 관리되다가 영속성 컨텍스트에서 분리되어 ,더 이상 영속성 컨텍스트에 의해 관리되지 않는 상태
- 삭제(removed)
: 엔티티를 영속성 컨텍스트와 데이터베이스에서 삭제한 상태

영속성 컨텍스트 : 1차 캐시
영속성 컨텍스트는 내부에 1차 캐시를 들고 있다.
em.persist()를 실행하면 엔티티가 영속성 컨텍스트 내부의 1차 캐시에 저장된다.이때 엔티티는 식별자 값(@Id로 테이블의 PK와 매핑한 값)으로 구분된다.

영속성 컨텍스트 : 엔티티 조회

영속성 컨텍스트 : 동일성 보장

영속성 컨텍스트 : 쓰기 지연

영속성 컨텍스트의 이점 : 엔티티 등록
- persist()로 엔티티를 영속화
- 엔티티는 영속성 컨텍스트 1차 캐시에 저장 && JPA가 엔티티를 분석해 INSERT 쿼리를 생성하여 쓰기 지연 SQL 저장소에 쌓아둠
-> transaction.commit();
- 트랜잭션을 커밋하면 쓰기 지연 SQL 저장소에 있는 쿼리들이 flush 되면서 DB에 날아간다.
- DB 트랜잭션 커밋.

영속성 컨텍스트의 이점 : 엔티티 수정, 변경 감지
- 변경 감지 : 엔티티의 변경사항을 DB에 자동으로 반영하는 기능
- 트랜잭션을 커밋
- 영속성 컨텍스트 내부에서 flush 호출
- 엔티티랑 스냅샷을 비교하여 변경된 엔티티 찾음
*스냅샷 : 1차 캐시 안에 들어오는 최초의 상태를 본떠둔 것
- 변경된 것은 UPDATE 쿼리를 생성하여 쓰기 지연 SQL 저장소에 보냄
- 쓰기 지연 저장소의 SQL을 DB에 보냄
- DB 트랜잭션 커밋.

영속성 컨텍스트의 이점 : 엔티티 삭제
- em.remove(memberA)로 삭제할 엔티티를 넘겨주면 DELETE 쿼리를 쓰기 지연 SQL 저장소에 등록
-> 이때 memberA 엔티티는 영속성 컨텍스트에서 제거됨
- 트랜잭션을 커밋하면 flush 호출하여 DB에 DELETE 쿼리 전달

플러시
- 플러시 : 영속성 컨텍스트의 변경 내용을 DB에 반영하는 것
플러시를 실행하면
- 변경 감지가 동작하여 영속성 컨텍스트에 있는 모든 엔티티와 스냅샷을 비교하여 수정된 엔티티를 찾음
- 수정된 엔티티는 UPDATE 쿼리를 만들어 쓰기 지연 SQL 저장소에 쌓아둠
- 쓰기 지연 SQL 저장소의 쿼리를 DB에 전송
영속성 컨텍스트를 플러시하는 방법
- em.flush() 메서드 호출
: 테스트나 다른 프레임워크와 JPA를 같이 사용할 때를 제외하고는 거의 사용하지 않는다.
- 트랜잭션 커밋 시 플러시 자동 호출
: JPA는 트랜잭션을 커밋할 때 플러시를 자동으로 호출한다.
- JPQL 쿼리 실행시 플러시 자동 호출
: JPA는 JPQL을 실행할 때도 플러시를 자동으로 호출한다.
즉시 로딩과 지연 로딩
1. 즉시 로딩
엔티티를 조회할 때 연관된 엔티티도 함께 조회
@ManyToOne(fetch = FetchType.EAGER)로 설정
2. 지연 로딩
연관된 엔티티까지 함께 조회할 필요는 없을 때 사용
@ManyToOne(fetch = FetchType .LAZY)로 설정한다.
@ManyToOne, @OneToOne과 같이 @XXXToOne 어노테이션들은 기본이 즉시 로딩(EAGER) 이다.
N+1 문제

1. findAll()을 한 순간 select t from Team t 이라는 JPQL 구문이 생성
2. 해당 구문을 분석한 select from team 이라는 SQL이 생성되어 실행된다.
3. DB의 결과를 받아 team 엔티티의 인스턴스들을 생성한다.
4. team과 연관되어 있는 user 도 로딩을 해야 한다.
5. 영속성 컨텍스트에서 연관된 user가 있는지 확인한다.
6. 영속성 컨텍스트에 없다면 3번에서 만들어진 team 인스턴스들 개수에 맞게 select from user where team_id = ? 이라는 SQL 구문이 생성된다. ( N+1 발생 )