📚FOS Study
홈카테고리
홈카테고리

카테고리

  • AI 페이지로 이동
    • RAG 페이지로 이동
    • agents 페이지로 이동
    • Claude Code의 Skill 시스템 - 개발자를 위한 AI 자동화의 새로운 차원
    • Claude Code 멀티 에이전트 — Teams
    • 멀티모달 LLM (Multimodal Large Language Model)
  • architecture 페이지로 이동
    • Cache-Aside 패턴
    • 디자인 패턴
    • 분산 트랜잭션
  • css 페이지로 이동
    • FlexBox 페이지로 이동
  • database 페이지로 이동
    • mysql 페이지로 이동
    • opensearch 페이지로 이동
    • redis 페이지로 이동
    • 김영한의-실전-데이터베이스-설계 페이지로 이동
    • 커넥션 풀 크기는 얼마나 조정해야할까?
    • 인덱스 - DB 성능 최적화의 핵심
    • 역정규화 (Denormalization)
    • 데이터 베이스 정규화
  • devops 페이지로 이동
    • docker 페이지로 이동
    • k8s 페이지로 이동
    • k8s-in-action 페이지로 이동
    • monitoring 페이지로 이동
  • go 페이지로 이동
    • Go 언어 기본 학습
  • http 페이지로 이동
    • HTTP Connection Pool
  • interview 페이지로 이동
    • 210812 페이지로 이동
    • 뱅크샐러드 AI Native Server Engineer
    • CJ 올리브영 지원 문항
    • CJ 올리브영 커머스플랫폼유닛 Back-End 개발 지원 자료
    • 마이리얼트립 - Platform Solutions실 회원주문개발 Product Engineer
    • NHN 서비스개발센터 AI서비스개발팀
    • nhn gameenvil console backend 직무 인터뷰 준비
    • 면접을 대비해봅시다
    • Tossplace Node.js Developer
    • 토스플레이스 Node.js 백엔드 컬처핏
  • java 페이지로 이동
    • jdbc 페이지로 이동
    • opentelemetry 페이지로 이동
    • spring 페이지로 이동
    • spring-batch 페이지로 이동
    • 더_자바_코드를_조작하는_다양한_방법 페이지로 이동
    • Java의 로깅 환경
    • MDC (Mapped Diagnostic Context)
    • OpenTelemetry 란 무엇인가?
    • Java StampedLock — 읽기 폭주에도 쓰기가 밀리지 않는 락
    • Virtual Thread와 Project Loom
  • javascript 페이지로 이동
    • Data_Structures_and_Algorithms 페이지로 이동
    • Heap 페이지로 이동
    • typescript 페이지로 이동
    • AbortController
    • Async Iterator와 제너레이터
    • CommonJS와 ECMAScript Modules
    • 제너레이터(Generator)
    • Http Client
    • Node.js
    • npm vs pnpm 선택기준은 무엇인가요?
    • `setImmediate()`
  • kafka 페이지로 이동
    • Kafka 기본
    • Kafka를 사용하여 **데이터 정합성**은 어떻게 유지해야 할까?
    • 메시지 전송 신뢰성
  • linux 페이지로 이동
    • fsync — 리눅스 파일 동기화 시스템 콜
    • tmux — Terminal Multiplexer
  • network 페이지로 이동
    • L2(스위치)와 L3(라우터)의 역할 차이
    • L4와 VIP(Virtual IP Address)
    • IP Subnet
  • react 페이지로 이동
    • JSX 페이지로 이동
    • VirtualDOM 페이지로 이동
    • v16 페이지로 이동
  • task 페이지로 이동
    • ai-service-team 페이지로 이동
    • nsc-slot 페이지로 이동
    • the-future-company 페이지로 이동
📚FOS Study

개발 학습 기록을 정리하는 블로그입니다.

바로가기

  • 홈
  • 카테고리

소셜

  • GitHub
  • Source Repository

© 2025 FOS Study. Built with Next.js & Tailwind CSS

목록으로 돌아가기
☕java/ jdbc

MySQL JDBC Cursor 방식

약 2분
2026년 2월 25일
2026년 3월 24일 수정
GitHub에서 보기

MySQL JDBC Cursor 방식

MySQL JDBC 드라이버의 기본 동작 방식과 대용량 처리 시 주의해야 할 Cursor(Streaming) 모드를 정리했다.


MySQL JDBC의 기본 동작: Fetch All

executeQuery()를 실행하면 드라이버가 결과셋 전체를 애플리케이션 메모리로 한 번에 가져온다. next()를 호출하면 메모리에 올라온 데이터를 순서대로 반환한다.

executeQuery() 호출
    → DB에서 전체 결과셋 조회
    → 애플리케이션 메모리(힙)에 전부 로드
    → next()로 하나씩 꺼냄 (DB 통신 없음)

장점: 네트워크 통신 1회 → 빠름 단점: 1,000만 건이면 힙에 전부 올라감 → OutOfMemoryError 위험


Cursor 기반 Streaming 모드

결과셋을 한 건씩(또는 배치 단위로) 가져오는 방식이다. 메모리에 전체를 올리지 않는다.

활성화 방법

1. URL 파라미터 방식 (useCursorFetch)

jdbc:mysql://localhost:3306/database?useCursorFetch=true

useCursorFetch=true를 설정하면 Statement.setFetchSize(n) 호출 시 실제로 n건씩 가져온다.

PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setFetchSize(1000);  // 1000건씩 가져옴
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
    // 처리
}

2. Integer.MIN_VALUE 방식 (Streaming)

useCursorFetch 없이도 setFetchSize(Integer.MIN_VALUE)를 설정하면 스트리밍 모드가 활성화된다.

stmt.setFetchSize(Integer.MIN_VALUE);  // 한 건씩 스트리밍

주의: 스트리밍 모드에서는 ResultSet이 열려있는 동안 같은 커넥션에서 다른 쿼리를 실행할 수 없다.


Spring Batch에서의 활용

Spring Batch의 JdbcCursorItemReader는 내부적으로 이 Cursor 방식을 사용한다.

@Bean
public JdbcCursorItemReader<MyEntity> reader(DataSource dataSource) {
    return new JdbcCursorItemReaderBuilder<MyEntity>()
        .name("myReader")
        .dataSource(dataSource)
        .sql("SELECT * FROM my_table WHERE status = 'PENDING'")
        .rowMapper(new MyEntityRowMapper())
        .fetchSize(1000)          // 1000건씩 커서로 가져옴
        .build();
}

JdbcPagingItemReader는 OFFSET/LIMIT 방식으로 페이지 단위 조회하는 것과 달리, JdbcCursorItemReader는 커서를 열어두고 순차적으로 읽는다. 정렬이 보장된 대용량 순차 처리에 적합하다.

Reader방식특징
JdbcCursorItemReaderDB 커서 유지단일 커넥션 점유, 대용량 순차 처리
JdbcPagingItemReaderOFFSET/LIMIT커넥션 재사용 가능, 페이지 처리

주의사항

  • 커넥션 점유 시간: Cursor 방식은 처리가 끝날 때까지 커넥션을 점유한다. 긴 배치 작업에서는 커넥션 풀이 고갈될 수 있다
  • 트랜잭션 범위: 커서가 열린 상태에서 트랜잭션이 커밋되면 커서가 닫힐 수 있다. Spring Batch chunk 처리 시 read() 단계와 write() 단계의 트랜잭션 경계를 이해해야 한다
  • MySQL 서버 부하: Cursor 모드에서 MySQL은 서버 측 커서를 유지한다. 동시에 많은 커서를 열면 서버 부하가 증가한다
java 카테고리의 다른 글 보기수정 제안하기

댓글

댓글을 불러오는 중...
목차
  • MySQL JDBC Cursor 방식
  • MySQL JDBC의 기본 동작: Fetch All
  • Cursor 기반 Streaming 모드
  • 활성화 방법
  • 1. URL 파라미터 방식 (useCursorFetch)
  • 2. Integer.MIN_VALUE 방식 (Streaming)
  • Spring Batch에서의 활용
  • 주의사항