Spring Boot JPA (2)
객체지향 쿼리 언어
JPQL, Criteria 쿠리, 네이티브 SQL, JDBC, MyBatis SQL 매퍼 프레임워크 사용
JPQL 특징
- 키워드는 대소문자 구분 안함
- 엔티티명을 사용
- 별칭이 필수
- TypedQuery — 반환타입이 명확한 경우 Query<TYPE> — 반환타입이 명확하지 않는 경우 Query<Object>
TypedQuery
- = : param 파라미터 이름으로 바인딩
- = ? 1 position 으로 바인딩
- =:#{} 자바 빈 이용
- ex String param = “yg”; “select user from User as user where user.name = :param” ;
QueryDsl
- SQL, JPQL 을 JAVA 코드로 작성 할 수 있도록 도와주는 Builder API
- Gradle 세팅후 빌드하게 되면 Qxx 엔티티를 생성하고 이 객체에 접근해 값을 얻을 수 있음
- gradle compileQuerydsl
- 장점
- 동적 쿼리가 수월하다 코드 베이스니까
- 컴파일시 에 쿼리 문제를 발견할 수 있다.
- 단점 ?
- 특정 조건이 만족하는지 찾는 쿼리는 아래 두 가지가 있을 수 있다. 그런데 성능은 exists를 사용 한게 훨신 좋을 수 있다 그런데 QueryDsl의 exist는 count를 사용한다고 한다. 즉 성능을 고려하면 exist 쿼리를 다시 정의해서 사용해줘야 한다.
- select exists(SELECT 1 FROM blog WHERE regdate > ‘2021-06-17 20:42:06.249332’)
- SELECT COUNT(*) FROM blog WHERE regdate > ‘2021-06-17 20:42:06.249332’
- 출처 https://kkambi.tistory.com/193
- 특정 조건이 만족하는지 찾는 쿼리는 아래 두 가지가 있을 수 있다. 그런데 성능은 exists를 사용 한게 훨신 좋을 수 있다 그런데 QueryDsl의 exist는 count를 사용한다고 한다. 즉 성능을 고려하면 exist 쿼리를 다시 정의해서 사용해줘야 한다.
Criteria
CriteriaBuilder cb = this.em.getCriteriaBuilder();
CriteriaUpdate<TYPE> update = cb.createCriteriaUpdate(TYPE.class)
this.em.createQuery(update).executeUpdate()
페이징
- setFirstResult(0)
- setMaxResults(2)
프로젝션
조회대상을 Entity자체로 한 경우 ,
특정값 조회시 DTO, 또는 VO 를 사용한다.
JOIN
innerJoin, outerJoin
fetch join :
연관된 엔티티나 컬렉션을 한번에 조회 가능 Fetch Type Lazy 타입을 Eager 로 만드는 .. 별칭 사용 불가, 프록시가 아닌 실제 Entity를 가져옴, SQL에서 제공하는 건 아니고 성능 향상을 위해 JPA 에서 제공하는것
준영속 상태에서도 객체 그래프 탐색가능
별칭불가 SELECT, WHERE, 서브쿼리, Paging 등에서는 fetch join 사용 불가
네이티브 SQL
ORM 사용하더라도 네이티브 SQL 써야 할 수 있다. JDBC, 마이바티스(SQL Mapper 프레임워크) 사용시 영속성 컨텍스트가 인지하지 못하는 잇슈 발생
@SqlResultSetMapping, @EntityResult, @FieldResult, @ColumnResult
Spring Data JPA
데이터 접근 계층 개발시 구현체 없이 인터페이스 만으로 개발 가능
Method : save, delete, find , getOne (엔티티를 프록시로 조회해옴)
쿼리메소드
Method 이름을 기반으로 JPA Query를 자동 생성 하는 기능 예) findByUserType, Method 생성 방식
아래 처럼 Query 애노테이션으로 Method의 Query를 지정할 수 있다. Query 가 복잡해 진다면 Named Query를 사용
- @Query(“select ….”)
- List<User> getUserxxxx
도메인 클래스 컨버터, 페이징 전략
트랜잭션 범위의 영속성 컨텍스트
동일 트랜잭션엔 동일 영속성 컨텍스트를 사용한다.
트랜잭션이 다르면 영속성 컨텍스트도 다르다
MVC 패턴에서 예를 들면 Service 에서의 영속성 컨택스트에 의한 데이터는 Controller 로 돌아오면 프록시만 남는다.(Lazy의 경우 )
준 영속 상태와 지연로딩 해결책
- 뷰가 필요한 엔티티를 미리 로딩하는 방법
- 글로벌 페치 전략 – N+1문제, 사용하지 않는 엔티티로딩
- JPQL 패치 조인 – 리포지토리 메소드 증가=> 프리젠테이션 계층이 데이터 접근 계층을 침범
- 강제 초기화 – 프리젠테이션 계층이 서비스 계층 침범
- 퍼사드 계층 추가
2. OSIV 이용
- open session in view – 영속성 컨텍스트를 뷰까지 열어둔다.
롤백
트랜잭션 롤백은 DB 반영사항만 롤백, 엔티티는 원복 안해줌
롤백의 경우에 영속성 컨택스트를 Clear 해서 사용 해야함
트랜잭션
원자성, 일관성, 격리성, 지속성
N+1 문제
JPA 사용시 성능 저하의 요인 => 패치 조인을 사용하라
M:N
github memo readme 참조
JPA 성능 최적화
- fetch type(LAZY, EAGER)을 정확하게 선택해야한다. (쿼리숫자를 줄여야한다.)
- Join 대신 Fetch Join – Join은 두 개 테이블을 읽음, Fetch Join 은 특정영역을 가져와서 Join 함으로 성능상 나을 수 있다.
- 최대한 바로 사용가능한 상태로 데이터를 가져오도록 쿼리를 구성해야 한다.
- 최대 절전모드 활용 ?
Repository 확장
- 쿼리 메서드나 @Query 등으로 처리할 수 없는 기능은 별도의 인터페이스로 설계
- xxxRepository, xxxRepositoryImpl 이런식으로
from 패스트캠퍼스 – 스프링아카데미아