상세 컨텐츠

본문 제목

11. JPA로 조회방법(FetchType) 설정하기

Java/코딩의 신

by Gopythor 2023. 12. 16. 14:30

본문

728x90
반응형

Fetch Type에 대해 공부.

사용자 테이블은 Board 테이블과 연관 되어 있음.

기존에 cascade와 orphanRemoval을 통해서 boards에 대한 데이터 처리를 해줌.

fetch에 대해 알아보자.

기존 작성문은 주석처리.

기본은 LAZY로 설정되어 있다.

Fetch는 2개 설정 할 수 있다.

board 클래스에 대한 데이터.

사용자 조회 시에 board 클래스에 대한 데이터를 같이 가져올 것인지, 아니면 나중에 필요할 때 가져올 것인지 그것에 대한 설정이다.

One으로 끝나는 것은 EAGER가 기본값.

Many로 끝나는 것은 LAZY가 기본값.

왜 기본값이 다른지 생각을 해보면

One으로 끝나는 것은 이것과 관련된 데이터가 하나의 행만 있다는 것이 보장이 됨.

기본적으로 함께 데이터를 조회해와도 성능상에 큰 무리가 없다.

Many 여러개의 데이터가 있다면, 코드 내에서 boards를 사용하지도 않는데 데이터를 가져오게 되면 성능상에 부하가 걸림.

실제로 데이터가 어떻게 처리가 되는지 확인해봄.

 

Many to Many에서 작성된 건은 Post man에서 어떻게 처리가 되는지 확인해볼 것임.

Get을 통해서 User 조회가 가능.

하나의 데이터만 가져와보도록 함.

id에 해당하는 사용자가 나옴.

3번 사용자 gildong을 가져와 볼것임.

권한과 게시글이 같이 나오고 있음.

권한이 나오지 않도록 권한에 @JsonIgnore 작성.

사용자 권한은 나오지 않음.

확인 해보려고 했던 것은 쿼리였는데 한줄로는 보기가 불편함.

해당 키워드를 구글링하면 나온다.

예전에 로깅 옵션을 지난번에 입력했었다.

format_sql도 추가해준다.

spring.jpa.properties.hibernate.format_sql=true

sql이 보기좋게 나옴.

그러나 조회가 2개가 됨.

우선 사용자 테이블을 먼저 가져왔음.

옵션을 LAZY로 줬음.

그리고 나중에 board를 가져옴.

그래서 따로 따로 조회가 된 것임.

처음에는 사용자 정보만 가져왔다가,

userApiController에서 리턴을 하면 JSON으로 변환을 해서

클라이언트에 그 정보를 보내주기 위해 Board 데이터가 필요하게 됨.

그렇기 때문에 JSON 타입으로 변환을 할 때에 정보가 필요하므로 그 때 조회하게 됨.

보드 정보를 넘겨주지 않는다 라고 어노테이션 설정.

그렇다면 하나만 출력이 될 것임.

Board가 출력되지 않음.

필요없는 데이터는 조회하지 않게 됨.

성능 상의 잇점이 있음.

지금 데이터가 몇개 없어서 상관이 없지만, 데이터가 10만개 정도 된다면, 굉장히 많은 차이가 있음.

이것을 EAGER로 바꾸게 되면, Board를 사용하지 않더라도

사용자 클래스만 가져올 때도, Board가 같이 조회가 될 것이다.

보는 것처럼 Board 정보가 필요가 없더라도

이번에는 조인이 걸렸다.

기본적으로 쿼리가 어떻게 처리가 되는지

로그가 출력이 되도록 설정을 해서 성능상에 문제가 없는지 확인을 해 가면서 설정을 해야 함.

이번에는 여러 데이터를 조회해보도록 하겠다.

id를 지우면 전체 사용자를 조회함.

 

SQL이 총 3개가 출력이 됨.

사용자를 먼저 조회를 해오고,

user id가 15인 게시글

user id가 3인 게시글

유저들에 해당하는 board를 조회함.

그래서 총 3개의 SQL이 출력됨.

만약 유저가 100명이 있으면, SQL이 100개가 호출이 됨.

user데이터까지 총 101개의 SQL이 호출됨.

사용자 건수 +1

SQL이 여러번 출력되는 것을 N+1문제라고 불린다.

성능이 문제가 생김.

해결하는 방법을 알아볼 것임.

findAll을 변수로 받도록 하겠음.

그리고 User클래스에서 EAGER를 LAZY로 변경.

코드상으로는 차이가 없음.

동일한 결과다.

그러나 쿼리가 하나 호출됐다.

실제로는 Board정보가 필요없기 때문에 그렇다.

아까는 EAGER로 설정을 해놨기 때문에 전체 데이터를 따로 따로 호출을 해서 users의 board를 전부 담았다.

이번에는 LAZY로 바꿨기 때문에 쿼리를 하나만 호출을 한 것이다.

size 같은 메소드를 호출하게 되면 board를 가져오게 된다.

2개의 쿼리문을 부름.

첫번째 유저에 해당하는 board 정보.

롬복을 사용하므로 slf4j로 로그를 사용할 수 있음.

debug호출.

Log.debug("get.Boards().size() : {}", users.get(0),getBoards().size());

에서 {}를 적으면, 결과값이 {}안에 표시가 된다.

현재 com.godcoder 패키지를 사용하고 있다.

logging.level.com.godcoder=DEBUG 설정을 하게 되면 해당 패키지에 DEBUG 레벨로 로그를 찍는 것이다.

다시 한 번 호출

사용자 정보를 먼저 호출

size 호출을 할 때, 조회를 하고 있다.

결과는 5이다.

호출하고 나서는 호출 후 가 나옴.

Boards가 사용 될 때, 그 사용자의 데이터만 조회.

왜냐하면 LAZY 설정이 됐기 때문이다.

문제는 데이터를 따로따로 가지고 오고 있다.

몇 가지 해결 방법이 있다.

Join으로 처리하기 위해서는 현재 버전의 도큐먼트 참조.

EntityGraph에 attributePaths가 있다.

보면 Repository에 설정을 하고 있다.

다시 정의를 해줘도 되고, 새롭게 메소드 명을 정의해도 된다.

지금 EntityGraph를 members에 주고 있다.

attributePaths는 User의 boards를 복사해서 주도록 한다.

 

이번에는 데이터가 join이 처리가 되서 조회가 된 것을 확인할 수 있다.

한번 @JsonIgnore를 없애고 다시 조회를 해보겠다.

모든 사용자가 조회가 됨.

작성한 게시글도 조회가 됨.

LAZY로 했을 때에는 Size를 호출을 할 때, 조회가 되지만,

EntitiyGraph를 주게 되면 FetchType이 무시가 된다.

findAll()을 하게 되면 한번에 조인이 일어난다.

 

fetch 타입에 따라서 데이터가 어떻게 조회가 되는지 알아봤음.

N+1 문제가 생겨서 성능 이슈가 생기면 EntityGraph 등을 이용해서 성능을 향상 시키도록 하라.

 

https://youtu.be/K3PU_rKtGLc?si=rZRI3aruDLoJH_We

 

728x90
반응형

관련글 더보기

댓글 영역