일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- HandlerMethodArgumentResolver
- @TransactionalEventListener
- #docker compose
- Linux
- 리팩토링 2판
- Stream
- JPA
- ksqldb
- intellij favorites
- 백명석님
- IntelliJ
- java
- Spring Cloud Netflix
- 친절한 SQL 튜닝
- 자바 ORM 표준 JPA 프로그래밍
- vue.js
- ksql
- javascript case
- 원격 브랜 삭제
- @Transactional Propagation
- git
- intellij 즐겨찾기
- 리눅스
- 자바 ORM 표준 JPA 프로그래밍 정리
- 마이크로 서비스
- intellij 핵심 단축키
- findTopBy
- aws
- CompletableFuture
- multipart테스트
- Today
- Total
시그마 삽질==six 시그마
JPA -객체 지향 쿼리언어 본문
우아한 형제들의 김영한 팀장님의 '자바 ORM 표준 JPA 프로그래밍'을
구입하시길 강력 추천드립니다.
책 구입을 원하시는분은 요기를 클릭하시면 됩니다.
저자 직강 인프런 강의도 있습니다 궁금하신분은 요기를 클릭
하단의 내용은 제가 예전에 읽었던 내용을 요약 정리한 것입니다.
1. JPQL ( Java Persistence Query Language )
1) 정의
테이블이 아닌 객체를 대상으로 검색하는 객체지향 쿼리임(객체지향 SQL)
SQL을 추상화해서 특정 DB SQL에 의존적이지 않음(방언만 변경해주면됨)
JPQL 사용하면 자동으로 SQL로 변환됨
JPQL은 별칭 필수임
2) 프로젝션
JPQL은 결과 반환시 연관관계 고려하지 않고 단지 SELECT 절에서 지정한 엔티티나 값만 조회한다.
(단 즉시로딩시 N+1로 연관객체 가져온다)
반환타입: TypeQuery(타입명확시) vs Query(타입 불명확) : Object(조회대상 1개) vs Object[] (조회대상2개이상)
getResultList() 결과 x시 ->빈컬렉션 반환 vs getSingleResult() 결과x시 ->예외, 결과2개이상-> 예외
이름으로 파리미터 바인딩(추천) vs 위치기준으로 바인딩(비추)
엔티티 프로젝션(영속성 관리 select b from Board b)
vs 임베디드 타입 프로젝션(영속성관리x, 조회의 시작점 될수없음.,임베디드 타입은 엔티티 타입x 값타입o ,pc관리대상x,임베디드 타입말고 엔티티만 from절 가능 )select a from address a (x), select o.address from order (o)
vs 스칼라타입 프로젝션(스칼라타입, select title from Board b)
vs 섞어서 조회(스칼라타입 +엔티티타입도 조회가능 , TypeQuery대신 Query사용, select title, b.reply from Board b)
em.createQuery 속에 new로 객체생성해서 거기에 담을수 있음(주의 1.전체클래스명사용 2. 순서와 타입일치하는 생성자필요)
3) Join
내부조인
내부 조인은 INNER JOIN을 사용한다. INNER는 생략가능
JPQL 큰 특징은 조인시 조인할 엔티티명을 넣는게 아니라 연관 필드를 넣는다는것
from Board b JOIN b.replies r 이지 from Board b JOIN Reply r 아님
서로다른 타입의 두 엔테티를 조회했으므로 TypeQuery를 사용할 수 없다. 따라서
List<Object[]> result=em.createQuery(query).getResultList();를 사용
외부조인
OUTER는 생략가능해서 LEFT JOIN으로 사용함
SELECT m FROM Member m LEFT JOIN m.team t on t.name='A'
컬렉션 조인
1:다, 다:다 관계처럼 컬렉션을 사용하는 곳에 조인하는 것을 컬렉션 조인이라 한다
SELECT t,m FROM Team t LEFT JOIN t.members m
세타조인
where 절을 사용하여 세타조인가능함(내부 조인만 지원)
select count(m) from Member m, Team t where m.username=t.name
4) 페치조인
조인의 종류는 아니고 JPQL에서 성능 최적화를 위해 제공하는 기능임
연관된 컬렉션을 한번에 같이 조회하는 기능 join fetch
일반 조인과 다르게 별칭 사용불가,둘 이상의 컬렉션을 페치할 수 없다.
(1)엔티티 패치조인
회원엔티티를 조회하면서 연관된 팀 엔티티도 함께 조회한다
select m from Member m join fetch m.team
(2)컬렉션 패치조인
1:다 , 다:다 팀을 조회하면서 패치조인을 사용해서 연관된 회원 컬렉션도(t.members) 함께 조회된다
JPQL: select t from Team t join fetch t.members where t.name='팀A'
SQL: select t.*, m.* from Team t inner join member M on T.id=M.team_id where t.name='팀A';
Team 테이블에서 팀A는 하나지만 Member테이블과 조인하면서 결과가 증가해서 조인결과 테이블을 보면 팀A가 두건 조회됨.
그래서 1:다, 다:다에서는 DISTINCT로 중복제거해야함
select distinct t from Team tjoin fetch t.members wher t.name='팀A'
(3) 패치조인 전략
패치조인은 >글로벌 로딩전략(지연로딩,즉시로딩) 보다 우선한다.(지연로딩 설정해도 가져온다)
둘 이상 컬렉션 패치 불가
1:다 경우 페치 조인시 페이징 api 사용불가 (board 1: reply : 다)
1:다 컬렉션 패치조인시 결과가 증가할 수 있지만 일대일,다대일 조인은 결과가 증가하지 않는다.
ex)
select b from Board b join fetch b.replies where b.title="안녕하세요"
selet B.* ,R.* FORM BOARD B INNER JOIN REPLY R ON B.ID=R.BOARD_ID WHERE B.TITLE="안녕하세요"
해당b에 연관된 reply 2개라면 board 2개생김!!!
(각각 그속에 reply2개씩 있음)
고로 DISTINCT로 중복제거해야함
JPQL의 DISTINCT명령어는 SQL에 DISTINCT를 추가하는것은 물론 애플리케이션에서 한번 더 중복을 제거한다.
JPQL:select distinct b from Board b join fetch b.replies where b.title="안녕하세요"
근데 sql 에 distinct해봤자 각 로우의 데이타 달라서 효과없음. 그러나 애플리케이션단에서 DISTINCT로 중복된 데이터를 걸러냄.
5) 경로 표현식
경로표현식: 쩜을 찍어서 객체 그래프를 탐색하는것
경로탐색을 사용한 묵시적조인은 항상 내부조인이다.
(1)상태필드 : 단순값저장하는 필드. 더 탐색 불가 ex) b.title
(2) 연관필드:연관 관계를위한 필드
class Member
Team team; 단일값 연관필드
List<Order> orders; 컬렉션값 연관필드
가)단일 값 연관 필드: 다:1, 1:1 인 경우. 묵시적 내부조인 발생, 계속탐색 가능 ex) r.board
외부조인 사용하려면 명시적으로 JOIN 키워드 사용해야함
묵시적 조인: select r.board from Reply r
명시적 조인: select r from Reply r JOIN r.board b
나)컬렉션 값 연관 경로: 1:다, 다:다인 경우. 묵시적 내부조인 발생. 컬렉션에값에서 추가로 더 탐색불가 ,단 from절에서 명시적 조인으로 별칭얻으면 가능 b.replies
select b.replies from Board b 성공 (컬렉션 값 자체는 ok!)
select b.replies.content from Board b 실패(컬렉션 값에서 추가로 경로탐색을 시도는 no!)
select r.content from Board b JOIN b.replies r 성공(컬렉션 값에서 추가로 경로탐색을 시도하려면 명시적 조인을 사용해서 새로운 별칭을 획득해야함)
select b.replies.size from Board b //count 반환함
6)서브쿼리
JPQL도 서브쿼리 지원 BUT where,having절만 사용가능하고 select ,from 절에서 사용불가
참고로 QueryDSL은 select,where서브쿼리는 지원하나 from 인라인뷰는 미지원.
7) JPQL 정적쿼리 vs 동적쿼리
(1)정적쿼리
미리 정의한 쿼리에 이름 부여해서 사용하는것.
@NamedQuery라고 어노테이션 사용해서 자바코드작성 or xml 문서에 작성
어노테이션 <xml 우선함
(2)동적쿼리
em.createQeury("select...)로 해서 직접 넘기는 것을 동적쿼리라함
8)벌크연산
벌크연산은 여러건을 한꺼번에 수정하거나 삭제한는것 excuteUpdate()
벌크연산은 영속성 컨텍스트 무시하고 DB에 직접쿼리하여 영속성컨텍스트와 DB 동기화가 안될 수 있음
방법1: 벌크연산 후 em.refresh()사용
방법2: 벌크연산을 가장 먼저 실행 후에 조회등등.. <--최선
방법3: 벌크연산 수행후 영속성 컨텍스트 초기화 (기존 영컨제거하는 방법임)<--차선
9)JPQL로 조회한 엔티티와 영속성 컨텍스트
JPQL 조회시 무조건 먼저 DB조회 후 기존 영속성 컨텍스트 있으면 DB조회한거 버리고 영속성 컨텍스트사용함.
고로 영속성 컨텍스틑 영속 상태인 엔티티 동일성보장(영속성 컨텍스트에 수정중인 데이터 보존위함)
find(): 영속성 컨텍스트에서 먼저 찾고 없으면 DB 조회(1차캐시)
JPQL: 선 DB조회후 영속성컨텍스트 있으면 DB버리고 영속사용
JPQL은 영속성 컨텍스트 무시하고 DB데이터 조회함.
의도치 않는 결과 막기위해 JPQL 실행전에 영속성 컨텍스트 내용을 DB에 반영해야함
다행히 JPA는 디폴트 플러시 모드가 FlushModeType.AUTO라(트랜잭션 커밋 직전이나 쿼리 실행 직전에 자동으로 플러시를 호출) 영속내용이 DB에 반영됨.
성능 최적화를 위해 FlushModeType.COMMIT(커밋시만 플러시)을 사용하는 경우가 있는데 그럴때는 em.flush()를 호출하자
2.Creteria 쿼리
JPQL을 편하게 작성하도록 도와주는 API, 빌더클래스 모음(프로그래밍 코드로 JPQL작성)
컴파일 시점에 오류를 발견,코드 자동완성기능,동적쿼리 작성 수월
3.네이티브 SQL
1) 정의 및 장점
JPQL 대신 직접 SQL 사용가능
특정 DB 기능제공(함수,힌트)/ 인라인뷰,UNION,INTERSECT 가능/ 스토어 프로시저 가능
특정 DB 기능 사용하는거라 해당 DB에 의존적이됨
JPA의 영속성 컨텍스트 그래도 사용가능. JDBC 직접사용은 영속성 컨텍스트 불가
em.createNativeQuery("select....)
2) 네이티브 SQL 정적쿼리 vs 동적쿼리
(1)정적쿼리
미리 정의한 쿼리에 이름 부여해서 사용하는것.
@NamedQuery라고 어노테이션 사용해서 자바코드작성 or xml 문서에 작성 <---xml을 추천!!
어노테이션 < xml 우선함
(2)동적쿼리
em.createQeury("select...)로 해서 직접 넘기는 것을 동적쿼리라함
4.QueryDSL
Creteria처럼 JPQL을 편하게 작성하도록 도와주는 빌더클래스 모음. 비표준(자바코드로 sql 작성)
uniqueResult(): 조회결과 1건일때 사용. 없으면 null반환, 하나이상 예외발생
singleResult(): uniqueResult()와 같지만 하나이상이면 처음 데이터를 반환
list(): 결과하나이상. 결과x시 빈컬렉션 반환
조인문법: 첫번째 p에 조인대상 두번째 p에 별칭사용할 쿼리타입 지정
동적쿼리: BooleanBuilder를 활용
QueryDSL장점
-컴파일 시점에 오류 잡아낼수 있다.
-JPQL은 파라미터 매핑해야되지만 JPQL은 안해도됨
-code assitance
5.JDBC직접사용 MyBatis 같은 SQL 매퍼 프래임워크 사용
JDBC나 MyBatis를 JPA에서 사용시 JPA는 그들을 인식못함
so 그들은 실행전 JPA를 강제 flush 시켜야 Dirty Read 없다.
'프로그래밍 > JPA' 카테고리의 다른 글
JPA- 영속성 관리 (0) | 2020.04.10 |
---|---|
스프링 데이터 JPA (0) | 2020.04.10 |
JPA -값 타입 (0) | 2020.04.09 |
JPA -프록시와 연관관계 관리 (0) | 2020.04.09 |
JPA -고급 매핑 (0) | 2020.04.09 |