-
Spring Batch with QuerydslItemReaderJPA 2020. 5. 2. 12:06반응형
무신사 java 개발팀에서는 다양한 배치 작업을 하고 있는데요
spring batch를 사용하여 배치 작업을 하고 있습니다
저희는 database에 접근하기 위해서 querydsl을 사용하고 있는데요
spring batch에서 querydsl을 지원해주고 있지 않습니다.
그래서 어쩔수 없이 작년에 코드를 만들었는데요 생각 보다 간단합니다.
필요하신 분들이 계실 것 같아서 공유하도록 하겠습니다.
저희가 실제로 실무에서 사용하고 있는 코드이기도 합니다만 기본 샘플이니 수정할 게 있다면 수정해서 사용해주세요!
package com.musinsa.batch.customreader; import com.musinsa.config.db.JpaSqlCustomQuery; import org.apache.commons.lang3.ObjectUtils; import org.springframework.dao.DataAccessResourceFailureException; import javax.persistence.EntityManager; import java.util.concurrent.CopyOnWriteArrayList; public class QuerydslItemReader<T> extends AbstractPagingCustomItemReader<T> { private JpaSqlCustomQuery<T> jpasqlCustomQuery; private EntityManager entityManager; private Callback callback; public QuerydslItemReader(JpaSqlCustomQuery<T> jpasqlCustomQuery) { this.jpasqlCustomQuery = jpasqlCustomQuery; } public QuerydslItemReader(JpaSqlCustomQuery<T> jpasqlCustomQuery, Callback callback) { this.jpasqlCustomQuery = jpasqlCustomQuery; this.callback = callback; } @Override protected void doOpen() throws Exception { super.doOpen(); entityManager = jpasqlCustomQuery.getEntityManager(); if (entityManager == null) { throw new DataAccessResourceFailureException("Unable to obtain an EntityManager"); } } @Override protected void doReadPage() throws Exception { if (results == null) { results = new CopyOnWriteArrayList<>(); } else { results.clear(); } int page = getPage(); int pageSize = getPageSize(); jpasqlCustomQuery.offset(page * pageSize).limit(pageSize); results.addAll(jpasqlCustomQuery.fetch()); if (ObjectUtils.isNotEmpty(callback)) { callback.call(results); } } @Override protected void doJumpToPage(int itemIndex) { } @Override protected void doClose() throws Exception { entityManager.clear(); super.doClose(); } }
참고로 AbstractPagingCustomItemReader는 복사해서 저희가 클래스로 따로 만들어서 그것을 상속해서 사용하도록 하고 있습니다
callback같은 경우에는 제거 해서 사용하도록 해주세요!
그러나 올려둔 이유는 있습니다 그 이유는 스프링 배치에서는 일대 다 조인을 해서 사용하기 보다는 1:1 관계에 있는 것만 조인을 해서 가져와서 1:N 조인 할 놈은 callback 함수에서 따로 다시 조인을 하거나 in 조건으로 가져오게 됩니다
일대 다 조인을 하게 되면 가져와야 될 사이즈가 너무 커지게 됩니다 물론 그렇게 됐을 때 사이즈가 얼마 안되면 상관이 없지만
배치 작업은 최소 메인 데이터가 몇십만건이기때문에 그놈이 일대 다 했을 경우 몇배가 커질 수도 있어서 callback클래스에 있는 call을 사용해서 처리 합니다 같은 데이터가 여러개 반복되서 전송될 경우 네트워크를 통해서 같은 데이터를 여러번 보내는 문제가 발생 할 수 있습니다 용량도 늘어나고 그러면 전송속도도 더 떨어지겠죠? 또한 db에서도 같은 데이터를 여러번 끌어올리는 문제도 있을거고요 물론 dbms의 캐싱이나 성능 개선으로 많이 개선이 되었겠지만 그래도 안하는게 성능에는 더 좋을 것 같습니다.
궁금한거 있으시면 댓글 달아주세요
반응형'JPA' 카테고리의 다른 글
QueryDsl where 조건에서 stringtemplate 사용하자 (0) 2021.07.14 spring batch에서 JPASQLQuery를 사용한 이유 (0) 2021.04.05 QueryDsl - char(1)보다는 varchar(1)을 사용하자 (0) 2019.10.21 QueryDsl from subquery와 join을 해보자! (10) 2019.09.03 QueryDsl - Date 작성시 Expressions.dateTemplate를 사용하자! (2) 2019.09.03