JPA 실전 예시설명 (기초개념 숙지 시, 보다 빠른 이해 도와줌)
★ Member Entity는 id, age가 존재한다고 가정
● findById() 사용시
1. EntityManager.find(Member.class, id) 실행
2. 영속성 컨텍스트 1차 캐시 조회
3. (존재 시) 1차 캐시 Entity 반환
3. (미존재 시) DB조회 후 조회 결과 Entity로 반환하여 1차 캐시에 넣은 후 1차 캐시 Entity 반환
● save() 사용시
1. EntityManager.persist(member) 실행
2. 영속성 컨텍스트 1차 캐시에 저장
3. 쓰기지연 SQL 저장소에 INSERT 쿼리저장
4. 트랜잭션이 커밋되기 전, flush를 수행하여 쓰기지연 SQL저장소의 모든 SQL을 DB에 전송해 Member Entity를 DB에 저장
● changeAge() 사용시
1. 변경할 Entity를 findById나 다른 방법으로 영속성 컨텍스트 혹은 DB에서 가져옴
2. 가져온 Entity를 1차 캐시에 저장 (스냅샷 자동 추가저장)
3. 해당 Entity의 필드 수정 (1차 캐시 데이터 수정)
4. 영속성 컨텍스트가 해당 Entity 1차 캐시와 스냅샷을 비교하여 변경된 필드 찾아냄 (Dirty Checking 수행)
5. 변경된 내용이 있는 경우, UPDATE 쿼리를 쓰기지연 SQL저장소에 저장
6. 트랜잭션이 커밋되기 전, flush를 수행하여 쓰기지연 SQL저장소의 모든 SQL을 DB에 반영
(Dirty Checking이 수행되어 변경된 필드 감지 시, 해당 변경내용 DB에 반영)
JPA관련 개념설명
JPA
● Java의 표준 ORM 기술 명세
ORM
● 객체와 RDB 사이의 패러다임 불일치를 해결하여 객체와 RDB를 매핑.
이를 통해 RDB를 객체처럼 다룰 수 있게 지원함
JDBC
● DB 종류에 관계없이 상호작용 할 수 있게끔 해주는 드라이버 (SQL을 텍스트로 작성하여 DB를 조작)
SQLMapper
● SQL문과 객체의 필드를 매핑하여 데이터를 객체화
EX) Spring JDBC, MyBatis
JPQL
● JPA에서 사용하는 객체지향 쿼리언어이며, Entity 객체를 대상으로 쿼리를 작성함
● 복잡한 쿼리 및 동적 쿼리 구현이 어려움
● 문자열로 쿼리를 작성하여, 코드 중복 및 에러 가능성 확률이 큼
Querydsl
● JPQL와 유사하나, Java코드로 작성되기 때문에 IDE의 자동완성을 사용할 수 있어 작성하기 간편함
● 복잡한 쿼리 및 동적 쿼리 구현이 용이함
● 컴파일 시점에 오류를 발견할 수 있어, 런타임에 오류 발생할 확률 적음
Entity Manager
● JPA에서 Entity 객체를 관리하는 주체
● 영속성 컨텍스트를 가지며, 영속성 컨텍스트는 JPA에서 Entity 객체를 관리하기 위한 작업 영역임
● Entity Manager는 영속성 컨텍스트와 데이터 베이스를 연결해주는 역할을 하며, Entity의 상태를 추적하고 변경사항을 관리하며 DB와의 일관성을 유지함
● Entity를 영속성 컨텍스트에 저장하면 해당 Entity는 DB와의 연결을 끊어도 영속성 컨텍스트에 남아있으며
DB와의 동기화가 필요한 시점에 변경사항을 반영함 (JDBC를 이용하여 DB와 연결됨)
영속성 컨텍스트
● Entity를 영구 저장하는 환경
● EntityManager.persist(entity)를 통해서 Entity를 영속성 컨텍스트에 저장
(중요한 포인트는 연동된 DB에 저장하지 않는다는 것!)
● EntityManager를 통해서 영속성 컨텍스트에 접근 할 수 있다.
영속성 컨텍스의 기능
> 1차 캐시
● Entity를 저장하는 공간이며, 조회 작업 시 1차 캐시부터 조회한 후 데이터가 없으면 DB를 조회하게 함
(DB까지 조회하지 않고도 엔티티 조회를 지원함. DB를 직접 조회하는 것은 리소스가 큰 작업이기 때문에 이를 통해 효율성을 증대시킬 수 있음)
작업과정
1. em.find()를 통해서 엔티티를 조회할 경우, 우선적으로 1차 캐시부터 먼저 탐색
2. 1차 캐시에서 탐색 후, 없는 경우 직접 DB로 쿼리를 날려 해당되는 엔티티를 가져와서 1차캐시에 저장하고, 1차 캐시에 있는 데이터를 반환해줌
> 쓰기지연 SQL 저장소
● Transaction이 Commit되는 시점에 flush를 통해 모든 SQL을 한번에 DB에 반영
(쿼리 1개마다 DB에 접근하는 것은 비효율적이므로, 한 작업에 연관된 쿼리들이 모두 쌓인 후 커밋 시점에 한꺼번에 보냄으로써 효율성을 증대시킬 수 있게 해줌)
작업과정
1. 영속성 컨텍스트에 해당 엔티티를 생성하고 위의 언급된 1차캐시에 저장.
2. Insert 문을 ‘쓰기 지연 SQL 저장소’에 넣어둠.
3. 커밋실행 시, flush()를 통해 SQL들이 한꺼번에 DB에 반영됨
> flush
● 영속성 컨텍스트의 변경내용을 데이터베이스에 반영해주는 명령어.
● 쓰기 지연 SQL 저장소의 쿼리를 DB로 날려줌
● tx.commit()을 할 경우 flush가 자동으로 호출됨. 이후 DCL commit이 실행됨
> Dirty Checking (상태 변경검사)
● 트랜잭션이 끝나는 시점에 변화가 있는 모든 Entity 객체를 DB에 자동반영 (이때 기준은 "최초 조회상태")
해주는 일종의 상태 변경 검사
작업과정
1. Entity를 조회하면 해당 조회 시점 기준으로 스냅샷을 만듦 (이때 1차 캐시 Entity와 스냅샷은 동일)
2. 트랜잭션 도중 Entity의 내용을 변경한 후 (1차 캐시 != 스냅샷) 커밋
3. JPA가 1차 캐시에 있는 모든 Entity를 스캔하여 스냅샷과 대조한 뒤, 변경된 것이 있다면 1차 캐시에 있는 데이터로 기존 내용이 변경되게끔 업데이트 쿼리를 쓰기지연 SQL저장소에 생성
4. flush()를 통해 DB에 반영
JPA 계층도
* Spring Data JPA를 사용하지 않으면 Class단에 @Repository를 작성하고 JPA를 적용한 다음 Entity Manager의 API를 직접 호출해야함.
Spring Data JPA의 Repository Interface에는 Entity Manager가 포함되었기 때문에 직접 작성하지 않아도 내부에서 자동적으로 호출을 지원함
'개인공부' 카테고리의 다른 글
Stream 활용예시 (0) | 2023.02.24 |
---|---|
Checked, Unchecked Exception 정리 (0) | 2023.02.20 |
2023.01.17 TIL (0) | 2023.01.17 |
2023.01.17 개인기록 (0) | 2023.01.17 |
2023.01.16 TIL (0) | 2023.01.16 |
댓글