Backend/Spring+Boot

QuerydslNoOffsetPagingItemReader fetchJoin

findmypiece 2022. 1. 6. 18:52
728x90

SpringBatch chunk 단위 처리 구현시 querydsl 을 사용하려고 했다. 그런데 SpringBatch 에서 querydsl 을 지원하지 않아 관련 Reader 구현체가 제공되지 않아 오픈소스로 제공되는 QuerydslNoOffsetPagingItemReader 를 사용했다. 

 

그런데 reader 쿼리의 fetchJoin 이 동작하지 않는다. 내가 구현한 reader는 대략 아래와 같다.

// 1. No Offset Option
val options: QuerydslNoOffsetNumberOptions<Test, Long> =
            QuerydslNoOffsetNumberOptions<Test, Long>(test.seq, Expression.ASC)

// 2. Querydsl Reader
return QuerydslNoOffsetPagingItemReader(entityManagerFactory, PAGE_SIZE, options) {
    queryFactory ->
        queryFactory
            .selectFrom(test)
            .innerJoin(test.subTest, subTest)
            .fetchJoin()
            .where(test.a.eq("test"))
}

 

test와 subTest 테이블을 inner join 하되 fetchJoin으로 지정했다. 그런데 아래와 같은 에러가 발생되며 진행이 되지 않았다.

query specified join fetching, but the owner of the fetched association was not present in the select list

 

번역기 돌리니 "쿼리가 조인 가져오기를 지정했지만 가져온 연결의 소유자가 선택 목록에 없습니다." 라는 뜻이다. 즉, fetchJoin으로 subTest를 한번에 가져오려고 했는데 select 절에 그게 없다는 것이다.

 

test Entity에는 subTest가 분명 포함되어 있다. 그럼에도 이런 에러가 발생하는 이유는 QuerydslNoOffsetPagingItemReader 의 동작방식 때문이다.

 

QuerydslNoOffsetPagingItemReader 에서는 noOffset 방식으로 쿼리를 처리하기 위해 읽어올 페이지에 해당하는 seq 의 min, max 값을 구해오는 쿼리를 우선수행한다.

 

문제는 그 때 select 절을 제외한 나머지는 위에서 람다로 지정한 JPAQuery 가 활용되기 때문에 아래와 같은 쿼리가 수행된다는 것이다.

select 
  min(test.seq) 
from 
  Test test   
inner join 
  fetch SubTest subTest with test.subTest = subTest
where test.a = 'test'


select 
  max(test.seq) 
from 
  Test test   
inner join 
  fetch SubTest subTest with test.subTest = subTest
where test.a = 'test'

 

정말로 fetchJoin 으로 subTest를 함께 읽어오려고 했는데 select 절에 그게 없다. 이런 이유로 QuerydslNoOffsetPagingItemReader 를 사용할 경우 reader 에서 fetchJoin 은 사용할 수 없다. 그냥 일반 join 을 사용해야 한다. 

 

QuerydslPagingItemReader 는 offset 방식으로 동작하는 걸로 알고 있는데 여기에서도 fetchJoin 을 사용할 수 없는지는 모르겠다. 이건 추후 확인되면 추가로 정리하는 걸로...

 

https://blog.leocat.kr/notes/2019/06/01/querydsl-avoid-n-plus-one-issue-with-fetch-join
https://www.inflearn.com/questions/23847
728x90