인프런 커뮤니티 질문&답변

iloveoov님의 프로필 이미지

작성한 질문수

스프링 배치

DB - JdbcCursorItemReader

JdbcCursorItemReader 쿼리 실행 시점과 ResultSet 동작 방식이 궁금합니다.

21.10.31 22:42 작성

·

673

3

안녕하세요.

AbstractCursorItemReader#doOpen() -> JdbcCursorItemReader#openCursor()에서

......
this
.rs = preparedStatement.executeQuery();
......

해당 시점에 쿼리가 실행이 되고, 이후 커넥션을 쭉 유지한채

AbstractCursorItemReader#doRead() -> JdbcCursorItemReader#readCursor(rs, currentRow)가 메소드가 호출될 때마다 DB에서 1row씩 데이터를 꺼내오는 방식으로 동작하는 것일까요?

 

openCursor에서 쿼리 실행 후 메모리에 쿼리 수행결과를 가지고 있다가 doRead() -> readCursor()를 수행하는건지 혼란이 와서 질문 드립니다.

 

JpaCursorItemReader의 경우는 

JpaCursorItemReader#doOpen()에서 쿼리 실행 후 결과를 메모리에 가지고 있다가 이때는 DB 커넥션 유지하지 않고, doRead() 호출시 한로우씩 반환하는 식으로 동작하는게 맞나요?  

 

 

 

답변 2

4

정수원님의 프로필 이미지
정수원
지식공유자

2021. 11. 01. 15:30

네 

전자가 맞습니다.

openCursor 에서는 DB 와 커넥션을 맺은 상태에서 커서를 처음 위치에 놓게 되고 

this.rs = preparedStatement.executeQuery();

readCursor 에서는 rs.next()  를 호출해서 실제 DB 에서 해당 커서의 레코드 즉 1개의 row 를 가지고 오게 됩니다.

protected T doRead() throws Exception {
if (rs == null) {
throw new ReaderNotOpenException("Reader must be open before it can be read.");
}

try {
if (!rs.next()) {
return null;
}
int currentRow = getCurrentItemCount();
T item = readCursor(rs, currentRow);
verifyCursorPosition(currentRow);
return item;
}
catch (SQLException se) {
throw getExceptionTranslator().translate("Attempt to process next row failed", getSql(), se);
}
}

위에서 

re.next() 할 때 DB 호출이 이루어지고 그 결과를 담은 rs 를 readCursor(rs, currentRow) 에 담아 호출하게 되면

protected T readCursor(ResultSet rs, int currentRow) throws SQLException {
return rowMapper.mapRow(rs, currentRow);
}

위의 rowMapper 에 rs 에 담긴 데이터를 매핑하게 됩니다.

결론적으로  cursor 방식은 rs 를 호출할 때마다 DB 의 커서를 이동하면서 데이터를 전달하는 방식이라 할 수 있습니다. 

다만 성능을 위해 cursor 방식으로 데이터를 불러올때 FetchSize 를 설정하게 되면 그 크기만큼 메모리로 가지고 온 다음 데이터를 읽을 수 있습니다.

적절한 FetchSize 를 설정하는 것이 좋습니다.

이종민님의 프로필 이미지

2023. 06. 02. 22:04

이해가 되었습니다 감사합니다

0

myeonjeong님의 프로필 이미지

2023. 03. 17. 14:46

안녕하세요 선생님.

비슷한 고민을 하다가 이 질문을 찾아오게 되었는데요,

예를들어 1000 건의 데이터가 있고, 100건씩 데이터를 처리하려고 하더라도

실제로 SQL 자체는 단 한번 실행되고,

데이터베이스 서버에서 해당 resultSet 을 가지고있으면서

cursor 를 batch application 으로 반환하고,

cursor 를 통해서 필요시 DB server 에 실제 데이터를 요청한다고 이해했습니다. (그리고 받은걸 메모리에 올려서 작업)

 

그러면 결국 DB 서버에서는 그 많은 데이터를 전부 메모리에 올려놓고 batch 작업이 종료될 때까지 유지해야한다고 이해했는데, 혹시 제가 이해한게 맞나요?!

iloveoov님의 프로필 이미지

작성한 질문수

질문하기