티스토리 뷰

spring batch 4.3 부터 JpaCursorItemReader 가 추가됐다. 이게 추가되기 이전에는 배치에서 JPA 를 쓸땐 JpaPagingItemReader 를 사용하거나 cursor 방식이 필요하다면 HibernateCursorItemReader 를 써야했다.

 

JpaCursorItemReader 가 추가된지 비교적 얼마 안됐기때문에 아직 HibernateCursorItemReader 를 이용해 돌아가고있는 배치가 많을 것으로 예상한다. 하지만 HibernateCursorItemReader 는 spring batch 5.0 부터 Deprecate 되었고, 5.2 부터는 아예 삭제될 예정이므로 최신 spring batch 에서 배치 로직을 작성하거나 기존 spring batch 프로젝트의 버전업을 고려하고있다면 HibernateCursorItemReader 를 사용할 수 없다. 아래는 HibernateCursorItemReader 의 javadoc 에서 가져온 내용이다.

Deprecated, for removal: This API element is subject to removal in a future version.
since 5.0 for removal in 5.2. Use the JpaCursorItemReader instead.

 

HibernateCursorItemReader 대신에 JpaCursorItemReader 를 사용하라고 하고있다.

 

그럼 JPA 가 등장한건 오래됐는데 JpaCursorItemReader 는 왜이리 늦게 나온걸까? JPA 자체 스펙에 stream 스펙이 비교적 최근에 추가됐기 때문이다.( https://thorben-janssen.com/whats-new-in-jpa-2-2/#stream-query-results )

이전에는 JPA 스펙으로 스트리밍을 지원하지 않았기 때문에 JPA 로 대량의 데이터를 처리하기 위해서는 오로지 페이징 기법만 사용해야했고, Hibernate 는 JPA 와 별개로 스트리밍처리를 지원했기에 HibernateCursorItemReader 만 존재했던 것이다.

 

그럼 JpaCursorItemReader 는 어떤 방식으로 스트리밍 처리를 지원할까? 일단 spring batch 가 제공하는 ItemReader 를 살펴보기전에 JPA 에 추가된 인터페이스를 살펴보자

 

해당 코드를 살펴보면 Stream 을 리턴하는 메서드가 디폴트 메서드로 추가되어있다.( https://github.com/jakartaee/persistence/blob/a3138b1d1a7f5d37eada7cc9d9f8aa36e818e09c/api/src/main/java/jakarta/persistence/Query.java#L95 )

default Stream getResultStream() {
    return getResultList().stream();
}

 

즉 이 디폴트 구현을 그대로 쓰면 스트리밍의 이점을 전혀 살릴 수 없다. 애플리케이션 단에서 getResultList() 로 조회결과를 모두 메모리에 올리고 그걸 그냥 스트리밍 처리하는 방식이기 때문이다. Hibernate 는 JPA 의 이 스펙을 구현하면서 기존부터 스트리밍을 처리하고있던 stream() 메서드를 이용하고있다. JPA 와 독자스펙으로 처리하고 있던걸 JPA 를 오버라이딩하면서 기존 코드를 내부적으로 이용하도록 하는 것이다. 그리고 결과적으로 이 스펙은 JDBC 를 이용해서 스트리밍을 처리하게 된다.

 

그리고 spring batch 의 JpaCursorItemReader 는 이러한 JPA 의 getResultStream() 을 활용하는 것인데 이렇다면 결국 최종 내부 구현은 JdbcCursorItemReader 나 JpaCursorItemReader 나 같은 메커니즘으로 도는것이다. 자바의 데이터베이스 표준이 JDBC 이고, ORM 역시 JDBC 에 기초해서 추상화를 제공하고있는 것이니 당연한 일일 것이다.

 

JPA 스펙에 추가된 getResultStream() 의 디폴트 메서드는 인터페이스 확장을 위한 기본 구현일 뿐이다. 이를 Hibernate 와 같은 각 JPA 구현체에서 제대로 오버라이딩해주지 않는다면 스트리밍의 역할을 하지 못하겠지만 이상한 구현체를 사용하는게 아닌 이상은 제대로 오버라이딩해서 스트리밍 처리를 잘 지원해주고 있다. 그리고 이를 기반으로 하고있는 JpaCursorItemReader 도 옵션을 잘 지정해서 사용한다면 기존 HibernateCursorItemReader, JdbcCursorItemReader 를 사용하는 것과 같은 이점을 누릴 수 있다.

 

참고로 JpaCursorItemReader 는 Jdbc, Hibernate 구현체와 달리 fetchSize 를 조절하는 옵션이 없다. 이는 구현체에 누락된 사항으로 spring batch 5.2 에서 옵션이 추가될 것으로 보인다.( https://github.com/spring-projects/spring-batch/issues/4479 )

# 참고자료

- https://vladmihalcea.com/whats-new-in-jpa-2-2-stream-the-result-of-a-query-execution/

- https://thorben-janssen.com/jpa-2-2s-new-stream-method-and-how-you-should-not-use-it/

- https://github.com/jakartaee/persistence

- https://github.com/hibernate/hibernate-orm

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
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 31
글 보관함