JPA 사용 이유
JPA란 Java Persistence API로 Java 진영의 ORM(Object-Relational-Mapping) 기술에 대한 표준 명세
- 생산성 증가
- SQL을 작성하고 JDBC API를 사용하는 반복적인 일을 대신 처리해준다.
- Object와 RDB 간의 패러다임 불일치 해결
- 객체의 경우 상속, 객체 그래프 탐색 등이 가능
JPA 패러다임의 불일치 해결
객체지향 프로그래밍
- 시스템의 복잡성을 제어할 수 있는 장치 제공 → 추상화, 상속, 캡슐화, 다형성
- 참조를 이용하여 다른 객체와 연관관계를 가진다.
- 동일성, 동등성을 이용하여 비교
관계형 데이터베이스
- 데이터 중심
- 추상화, 상속, 캡슐화, 다형성과 같은 개념은 없다
- 외래 키를 사용해서 다른 테이블과 연관관계를 가진다.
- PK 값으로 ROW를 구분
JPA의 상속 관계 해결
class Item { }
class Album extends Item { }
em.persist(Album);
em.find(Album.class, albumId);
- JPA는
em.persist(Album)
을 통해 INSERT INTO ITEM
과 INSERT INTO ALBUM
을 실행하게 된다.
- JPA는
em.find(Album.class, albumId)
을 하게되면 JOIN을 이용하여 필요한 데이터를 가져온다.
- 상속관계 매핑을 이용
- JOINED
- SINGLE_TABLE
- TABLE_PER_CLASS
JPA의 연관관계 해결
- 만약 객체를 데이터베이스 방식에 맞추면 참조를 이용할 수 없다.
- 객체지향 모델링을 적용(외래키가 아닌 참조를 이용하도록)하기 위해서는 인간 매퍼가 필요하다(노가다가 필요하다는 뜻).
- 이러한 번거롭고 힘든일을 JPA가 해준다.
- JPA는 연관관계에서 패러다임 불일치를 해결해준다.
JPA 객체 그래프 탐색 해결
- 객체는 참조를 사용해서 연관된 객체를 찾을 수 있다.
- SQL을 직접 다루게 되면 SQL에 의해 객체 그래프 탐색 범위가 제한된다.
- JPA는 연관된 객체를 사용하는 시점에 적절한 query를 실행하여 객체 그래프 탐색의 범위에 제한이 없도록 한다.(Lazy Loading)
JPA 비교 해결
- JPA는 동일한 트랜잭션에서 객체의 동일성을 보장한다.
패러다임 불일치 해결 관련
N+1 문제
- 즉시 로딩
- Spring Data JPA 메서드를 이용하여 조회하게 되는 경우 join을 이용해서 연관있는 객체까지 가져오게 된다
- 하지만 JPQL을 이용하게되면 N+1 문제가 발생하게 된다.
JPQL에선 입력 받은 query string이 그대로 SQL로 변환된다. "select m from Member m" 이 문장으로 당연히 Member만 SELECT 하게 된다. MEMBER를 쭉 다 가져와서 보니까 어 근데, Member 엔티티의 Team의 fetchType이 EAGER네? LAZY면 프록시를 넣으면 되겠지만, EAGER는 반환하는 시점에 다 조회가 되어 있어야 한다. 따라서, Member를 다 가져오고 나서, 그 Member와 연관된 Team을 다시 다 가져온다.
default_batch_fetch_size
- 컬렉션 페치 조인 페이지 불가능 → 컬렉션 레이지 로딩 + 페이징 가능 + 최적화가 가능한 방법
- 컬렉션이나 프록시 객체를 한꺼번에 정해놓은 개수 만큼 미리 당겨 놓는다.(in 쿼리에 정해 높은 개수 만큼 포함된다)
- 1 + N → 1 + 1
JPA의 save와 saveAll의 성능 차이
save
는 1개 저장
saveAll
은 안에 들어가 있는 N개의 데이터를 저장
N건의 데이터를 save와 saveAll을 사용해서 저장하게 된다면?
saveAll의 성능이 더 좋다.
왜
save
의 경우 n번의 proxy 과정(@Transactional
, n번의 새로운 트랜잭션 생성)을 거치게 된다.
![](https://velog.velcdn.com/images/yshjft/post/c3821f02-eb4a-4513-b3af-5c53e255c90d/image.png)
saveAll
의 경우 1번의 proxy 과정(@Transactional
, 1번의 트랙잭션을 지속해서 사용)을 거치게 된다.
![](https://velog.velcdn.com/images/yshjft/post/647df41f-f817-4c8f-a540-fdf6ff45ce31/image.png)
JPA OSIV
OSIV(Open Session In View, Open EnitityManager In View)
데이터베이스 커낵션을 언제 반환할지 설정하는 옵션
(default) spring.jpa.open-in-view = true
- 트랙잭션이 끝나도 반환을 하지 않는다.
- 트랜잭션이 끝나도 api나 view 응답이 반환될 때까지 영속성 컨텍스트를 살려둔다.
- ADMIN 에서 사용 권장
spring.jpa.open-in-view = false
- 트랜잭션이 끝나면 반환
- 트랜잭션이 끝나면 영속성 컨텍스트 정리
- 서비스에서 사용 권장