본문 바로가기
삽질일기/트러블 슈팅

Spring Batch JpaPagingItemReader 사용 시 주의사항

by 권성호 2023. 7. 2.

사실이 아니라 공부한 내용과 생각을 정리한 글입니다. 언제든 가르침을 주신다면 감사하겠습니다.

 

스프링 배치의 청크 프로세싱은 Item에 대한 읽기, 처리, 쓰기 작업을 Reader, Processor, Wirter로 잘 추상화해 두었다.

따라서 일반적으로 Reader 는 읽는 역할을 한다고 생각했다. 하지만 JpaPagingItemReader 는 단순히 읽는 역할 이상을 한다. 

JpaPagingItemReader#doReadPage 메소드의 코드를 보자.

    protected void doReadPage() {
        EntityTransaction tx = null;
        if (this.transacted) {
            tx = this.entityManager.getTransaction();
            tx.begin();
            this.entityManager.flush();
            this.entityManager.clear();
        }

        Query query = this.createQuery().setFirstResult(this.getPage() * this.getPageSize()).setMaxResults(this.getPageSize());
        if (this.parameterValues != null) {
            Iterator var3 = this.parameterValues.entrySet().iterator();

            while(var3.hasNext()) {
                Entry<String, Object> me = (Entry)var3.next();
                query.setParameter((String)me.getKey(), me.getValue());
            }
        }

        if (this.results == null) {
            this.results = new CopyOnWriteArrayList();
        } else {
            this.results.clear();
        }

        if (!this.transacted) {
            List<T> queryResult = query.getResultList();
            Iterator var7 = queryResult.iterator();

            while(var7.hasNext()) {
                T entity = var7.next();
                this.entityManager.detach(entity);
                this.results.add(entity);
            }
        } else {
            this.results.addAll(query.getResultList());
            tx.commit();
        }

    }

transacted 가 ture 일 때의 동작을 살펴보면, 쿼리를 실행하기 전 영속성콘텍스트를 flush, clear 하는 것을 확인할 수 있다.

이는 이전 청크 처리에서 조회한 엔티티를 디비에 반영한다는 의미이다.

즉, transacted 가 true 일 때 JpaPagingItemReader 는 지정된 쿼리 수행을 통해 조회해 온 엔티티를 자신이 가지고 있는 영속성콘텍스트에 저장해 두고 다음 청크프로세싱 때 변경사항을 디비에 반영하는 일을 한다.

 

처음에는 JpaPagingItemReader 는 단순히 디비로부터 조회하는 역할만 있는 줄 알고 사용했다가 원치 않는 디비 데이터의 변경 혹은 Locking Exception을 경험했었고 이 동작이 이상하다고 느꼈다.

하지만 다시 곱씹어보니 자바 어플리케이션에서 객체의 변경만으로 디비가 변경되는 것은 원래의 Jpa 사상과 일치하였기 때문에 이러한 동작이 이해되는 점도 있었다.

 

결론적으로, 최초에 내가 생각했던 단순 디비데이터 읽기의 역할만 하려면 JpaPagingItemReader를 생성할 때 transacted 옵션을 false로 주면 된다.

 

 

 

 

 

댓글