Spring Batch 입문 47편. JobRepository 의 DB 메타데이터 테이블 6개 — BATCH_JOB_INSTANCE · BATCH_JOB_EXECUTION · BATCH_JOB_EXECUTION_PARAMS · BATCH_JOB_EXECUTION_CONTEXT · BATCH_STEP_EXECUTION · BATCH_STEP_EXECUTION_CONTEXT. ERD · DDL · 컬럼별 의미, 운영자가 직접 쿼리하는 권장 SQL, optimistic locking VERSION column, 시리즈 통틀어 등장한 batch 용어 정리까지. Part 11 의 두 번째.
이 글은 Spring Batch 입문에서 운영까지 시리즈 48편 중 47편이에요. 46편 JFR(Java Flight Recorder, JVM 내장 프로파일러) 다음 — Spring Batch 가 DB 에 어떻게 metadata 를 저장하는가 — Meta-Data Schema + 시리즈 통틀어 등장한 용어 정리.
왜 metadata schema 를 알아야 하나
운영 환경에서는 어떤 Job 이 언제 실행됐는지 DB 를 직접 조회하고, 재시작 가능한 JobInstance 를 확인하고, 실패한 Step 의 ExecutionContext(실행 중 상태 저장소) 를 검토하고, 비정상 종료를 detection 하고, 오래된 metadata 를 정리(디스크 관리) 합니다. 그래서 JobExplorer API 외에 SQL 로 직접 접근 하는 것이 운영자의 강력한 무기예요.
6 테이블 + 3 sequence
| 테이블 | 도메인 객체 | 의미 |
|---|---|---|
BATCH_JOB_INSTANCE |
JobInstance |
Job 의 논리 instance |
BATCH_JOB_EXECUTION |
JobExecution |
한 번의 실행 |
BATCH_JOB_EXECUTION_PARAMS |
JobParameters |
실행 시 파라미터 |
BATCH_JOB_EXECUTION_CONTEXT |
ExecutionContext (Job) |
Job 단위 상태 |
BATCH_STEP_EXECUTION |
StepExecution |
Step 실행 |
BATCH_STEP_EXECUTION_CONTEXT |
ExecutionContext (Step) |
Step 단위 상태 |
여기에 sequence 3개가 붙어요 — BATCH_JOB_INSTANCE_SEQ, BATCH_JOB_EXECUTION_SEQ, BATCH_STEP_EXECUTION_SEQ. DB 가 sequence 를 지원하지 않는 MySQL 같은 경우엔 table 로 흉내 내는데 그게 MySQLMaxValueIncrementer 예요.
ERD 관계
BATCH_JOB_INSTANCE (1)
│
│ JOB_INSTANCE_ID
↓
BATCH_JOB_EXECUTION (*) ──── BATCH_JOB_EXECUTION_PARAMS (*)
│ ──── BATCH_JOB_EXECUTION_CONTEXT (1)
│ JOB_EXECUTION_ID
↓
BATCH_STEP_EXECUTION (*) ──── BATCH_STEP_EXECUTION_CONTEXT (1)
JobInstance 와 JobExecution 은 1 대 N 관계예요 — 재시작 시 같은 instance 에 새 execution 이 붙죠. JobExecution 과 StepExecution 도 1 대 N — 한 Job 안에 여러 Step 이 들어가니까요.
DDL 예제 — 표준 H2/PostgreSQL
DDL(Data Definition Language, 스키마 정의 SQL) 예제를 보면서 컬럼이 뭘 의미하는지 짚어볼게요.
BATCH_JOB_INSTANCE
CREATE TABLE BATCH_JOB_INSTANCE (
JOB_INSTANCE_ID BIGINT PRIMARY KEY,
VERSION BIGINT,
JOB_NAME VARCHAR(100) NOT NULL,
JOB_KEY VARCHAR(32) NOT NULL
);
| 컬럼 | 의미 |
|---|---|
JOB_INSTANCE_ID |
PK |
VERSION |
optimistic lock |
JOB_NAME |
Job 이름 |
JOB_KEY |
JobParameters 의 hash (instance 식별 키) |
핵심은 JOB_KEY 가 JobParameters 의 직렬화 hash 라는 점이에요. 동일 JobParameters = 동일 JobInstance 메커니즘이 여기서 나옵니다.
BATCH_JOB_EXECUTION_PARAMS
CREATE TABLE BATCH_JOB_EXECUTION_PARAMS (
JOB_EXECUTION_ID BIGINT NOT NULL,
PARAMETER_NAME VARCHAR(100) NOT NULL,
PARAMETER_TYPE VARCHAR(100) NOT NULL,
PARAMETER_VALUE VARCHAR(2500),
IDENTIFYING CHAR(1) NOT NULL,
CONSTRAINT JOB_EXEC_PARAMS_FK FOREIGN KEY (JOB_EXECUTION_ID)
REFERENCES BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
);
각 JobExecution 의 parameter 별 row 가 저장돼요. IDENTIFYING 컬럼은 Y/N 값을 가지는데, Y 인 parameter 만 JobInstance 식별 에 기여합니다 (JOB_KEY hash 에 들어가요).
BATCH_JOB_EXECUTION
CREATE TABLE BATCH_JOB_EXECUTION (
JOB_EXECUTION_ID BIGINT PRIMARY KEY,
VERSION BIGINT,
JOB_INSTANCE_ID BIGINT NOT NULL,
CREATE_TIME TIMESTAMP NOT NULL,
START_TIME TIMESTAMP,
END_TIME TIMESTAMP,
STATUS VARCHAR(10),
EXIT_CODE VARCHAR(20),
EXIT_MESSAGE VARCHAR(2500),
LAST_UPDATED TIMESTAMP,
CONSTRAINT JOB_INSTANCE_EXECUTION_FK FOREIGN KEY (JOB_INSTANCE_ID)
REFERENCES BATCH_JOB_INSTANCE(JOB_INSTANCE_ID)
);
| 컬럼 | 의미 |
|---|---|
STATUS |
BatchStatus (COMPLETED · STARTED · FAILED · STOPPED · ABANDONED · UNKNOWN) |
EXIT_CODE |
ExitStatus 의 exitCode |
EXIT_MESSAGE |
실패 시 stack trace |
START_TIME / END_TIME |
실행 시작/종료 |
END_TIME = NULL + STATUS = STARTED |
abnormal termination (JVM(Java Virtual Machine, 자바 실행 환경) 죽음 등) |
BATCH_STEP_EXECUTION
CREATE TABLE BATCH_STEP_EXECUTION (
STEP_EXECUTION_ID BIGINT PRIMARY KEY,
VERSION BIGINT NOT NULL,
STEP_NAME VARCHAR(100) NOT NULL,
JOB_EXECUTION_ID BIGINT NOT NULL,
CREATE_TIME TIMESTAMP NOT NULL,
START_TIME TIMESTAMP,
END_TIME TIMESTAMP,
STATUS VARCHAR(10),
COMMIT_COUNT BIGINT,
READ_COUNT BIGINT,
FILTER_COUNT BIGINT,
WRITE_COUNT BIGINT,
READ_SKIP_COUNT BIGINT,
WRITE_SKIP_COUNT BIGINT,
PROCESS_SKIP_COUNT BIGINT,
ROLLBACK_COUNT BIGINT,
EXIT_CODE VARCHAR(20),
EXIT_MESSAGE VARCHAR(2500),
LAST_UPDATED TIMESTAMP,
CONSTRAINT JOB_EXECUTION_STEP_FK FOREIGN KEY (JOB_EXECUTION_ID)
REFERENCES BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
);
핵심 통계 컬럼을 살펴보면, COMMIT_COUNT 는 chunk commit 횟수, READ_COUNT 는 읽은 item, FILTER_COUNT 는 ItemProcessor 가 null 을 반환한 횟수(35편), WRITE_COUNT 는 write 한 item, READ_SKIP_COUNT · WRITE_SKIP_COUNT · PROCESS_SKIP_COUNT 는 14편에서 다뤘던 skip 통계예요. ROLLBACK_COUNT 는 chunk rollback 횟수로 retry 와 skip recovery 도 포함합니다. 이 컬럼들 덕분에 Step 의 health 가 SQL 하나로 진단되는 거예요.
BATCH_JOB_EXECUTION_CONTEXT · BATCH_STEP_EXECUTION_CONTEXT
CREATE TABLE BATCH_JOB_EXECUTION_CONTEXT (
JOB_EXECUTION_ID BIGINT PRIMARY KEY,
SHORT_CONTEXT VARCHAR(2500) NOT NULL,
SERIALIZED_CONTEXT CLOB,
CONSTRAINT JOB_EXEC_CTX_FK FOREIGN KEY (JOB_EXECUTION_ID)
REFERENCES BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
);
CREATE TABLE BATCH_STEP_EXECUTION_CONTEXT (
STEP_EXECUTION_ID BIGINT PRIMARY KEY,
SHORT_CONTEXT VARCHAR(2500) NOT NULL,
SERIALIZED_CONTEXT CLOB,
CONSTRAINT STEP_EXEC_CTX_FK FOREIGN KEY (STEP_EXECUTION_ID)
REFERENCES BATCH_STEP_EXECUTION(STEP_EXECUTION_ID)
);
| 컬럼 | 의미 |
|---|---|
SHORT_CONTEXT |
ExecutionContext 의 JSON(JavaScript Object Notation, 텍스트 직렬화 포맷) 문자열 (조회용) |
SERIALIZED_CONTEXT |
binary 직렬화 (실제 복구용) |
24편에서 본 ItemStream open 시점에 복구 동작의 데이터 출처가 바로 이 테이블이에요.
Optimistic Locking — VERSION 컬럼
Each time a record is "touched" (updated), the value in the version column is incremented by one. — 공식 reference
VERSION 컬럼은 optimistic concurrency control(낙관적 동시성 제어) 용도예요.
UPDATE BATCH_JOB_EXECUTION
SET ..., VERSION = VERSION + 1
WHERE JOB_EXECUTION_ID = ? AND VERSION = ?
업데이트 시 version 일치 를 검사하고, 불일치면 OptimisticLockingFailureException 이 떨어져요. 같은 batch 가 여러 서버에서 동시 실행됐을 때 충돌을 detection 하는 장치죠.
Schema Initialization
Spring Boot 에서는 이렇게 설정해요.
spring:
batch:
jdbc:
initialize-schema: always # always · embedded · never
| 값 | 동작 |
|---|---|
always |
매 시작 시 schema 생성 (테스트) |
embedded |
H2·Derby 같은 embedded DB 만 (default) |
never |
수동 관리 (운영 권장) |
운영은 never 로 두고 DBA(Database Administrator, DB 관리자) 가 명시 schema 를 직접 관리 합니다.
명시 DDL
Spring Batch core jar 안에 org/springframework/batch/core/schema-*.sql 이 들어있어요. DB 별로 (h2 · postgresql · mysql · oracle 등) 따로 있습니다.
# jar 안 schema-postgresql.sql 추출
unzip spring-batch-core-6.0.0.jar 'org/springframework/batch/core/schema-postgresql.sql'
DBA 가 prod DB 에 적용하면 끝이에요.
Migration Scripts
Migration scripts are organized into folders corresponding to version numbers. — 공식 reference
버전 upgrade 시 schema 변경이 따라오는데, migration/2.2/ (2.2 이전 → 2.2), migration/4.1/ (4.1 이전 → 4.1) 같은 식으로 폴더가 나뉘어 있어요. 운영 upgrade 는 반드시 migration script 를 확인하고 적용 해야 합니다.
운영 권장 SQL — 자주 쓰는 query
1. 최근 실패한 Job
SELECT
ji.JOB_NAME,
je.JOB_EXECUTION_ID,
je.START_TIME,
je.END_TIME,
je.STATUS,
je.EXIT_CODE,
je.EXIT_MESSAGE
FROM BATCH_JOB_EXECUTION je
JOIN BATCH_JOB_INSTANCE ji ON je.JOB_INSTANCE_ID = ji.JOB_INSTANCE_ID
WHERE je.STATUS = 'FAILED'
AND je.START_TIME > NOW() - INTERVAL '24 hours'
ORDER BY je.START_TIME DESC;
2. 비정상 종료 Detect
-- STARTED 상태인데 일정 시간 이상 update 없음
SELECT
JOB_EXECUTION_ID,
JOB_INSTANCE_ID,
START_TIME,
LAST_UPDATED,
NOW() - LAST_UPDATED AS stale_for
FROM BATCH_JOB_EXECUTION
WHERE STATUS = 'STARTED'
AND LAST_UPDATED < NOW() - INTERVAL '1 hour';
JVM 죽음이나 crash 후에 STARTED 상태가 잔존 하는 경우, 운영자가 수동으로 ABANDONED 처리합니다.
3. Step 별 처리 통계
SELECT
ji.JOB_NAME,
se.STEP_NAME,
se.STATUS,
se.READ_COUNT,
se.WRITE_COUNT,
se.FILTER_COUNT,
se.READ_SKIP_COUNT + se.WRITE_SKIP_COUNT + se.PROCESS_SKIP_COUNT AS total_skip,
se.ROLLBACK_COUNT,
se.END_TIME - se.START_TIME AS duration
FROM BATCH_STEP_EXECUTION se
JOIN BATCH_JOB_EXECUTION je ON se.JOB_EXECUTION_ID = je.JOB_EXECUTION_ID
JOIN BATCH_JOB_INSTANCE ji ON je.JOB_INSTANCE_ID = ji.JOB_INSTANCE_ID
WHERE je.START_TIME > NOW() - INTERVAL '7 days'
ORDER BY je.START_TIME DESC;
4. JobInstance 별 재시도 횟수
SELECT
ji.JOB_NAME,
ji.JOB_INSTANCE_ID,
COUNT(je.JOB_EXECUTION_ID) AS execution_count,
SUM(CASE WHEN je.STATUS = 'COMPLETED' THEN 1 ELSE 0 END) AS completed,
SUM(CASE WHEN je.STATUS = 'FAILED' THEN 1 ELSE 0 END) AS failed
FROM BATCH_JOB_INSTANCE ji
JOIN BATCH_JOB_EXECUTION je ON ji.JOB_INSTANCE_ID = je.JOB_INSTANCE_ID
GROUP BY ji.JOB_NAME, ji.JOB_INSTANCE_ID
HAVING COUNT(je.JOB_EXECUTION_ID) > 1
ORDER BY ji.JOB_INSTANCE_ID DESC;
여러 번 재시도된 JobInstance 는 문제가 자주 발생하는 지점이에요.
5. JobParameters 검색
SELECT
je.JOB_EXECUTION_ID,
je.STATUS,
p.PARAMETER_NAME,
p.PARAMETER_VALUE
FROM BATCH_JOB_EXECUTION_PARAMS p
JOIN BATCH_JOB_EXECUTION je ON p.JOB_EXECUTION_ID = je.JOB_EXECUTION_ID
WHERE p.PARAMETER_NAME = 'input.file'
AND p.PARAMETER_VALUE LIKE '%2026-05%';
특정 파일이나 날짜로 실행된 Job 을 찾을 때 써요.
6. 오래된 metadata 정리
-- 90일 이상 된 완료된 JobExecution 삭제 (cascade FK 주의)
DELETE FROM BATCH_STEP_EXECUTION_CONTEXT
WHERE STEP_EXECUTION_ID IN (
SELECT STEP_EXECUTION_ID FROM BATCH_STEP_EXECUTION
WHERE JOB_EXECUTION_ID IN (
SELECT JOB_EXECUTION_ID FROM BATCH_JOB_EXECUTION
WHERE STATUS = 'COMPLETED' AND END_TIME < NOW() - INTERVAL '90 days'
)
);
-- 같은 패턴으로 STEP_EXECUTION · JOB_EXECUTION_CONTEXT · JOB_EXECUTION_PARAMS · JOB_EXECUTION · JOB_INSTANCE 순서 삭제
40편에서 본 JobRepositoryTestUtils.removeJobExecutions() 의 운영 버전이에요. FK 순서 주의 — child 부터 parent 순으로 지워야 합니다.
7. STARTED 잔존 abandon 처리
-- 죽은 batch 의 STARTED 를 ABANDONED 로
UPDATE BATCH_JOB_EXECUTION
SET STATUS = 'ABANDONED',
EXIT_CODE = 'ABANDONED',
EXIT_MESSAGE = 'Manually abandoned due to abnormal termination',
END_TIME = NOW(),
LAST_UPDATED = NOW(),
VERSION = VERSION + 1
WHERE JOB_EXECUTION_ID = ?;
JVM crash 후 재시작 가능한 상태로 복구 하는 SQL 이에요. VERSION 증가를 잊지 말 것 — optimistic lock 때문에 빠뜨리면 동작이 꼬여요. 운영자의 최후 수단 이고 실수 위험이 큰 만큼 조심해서 써야 합니다.
Glossary — 시리즈 통틀어 등장한 용어
핵심 개념
Batch = 시간 축적 비즈니스 transaction 집합.
Batch Window = batch job 이 완료되어야 하는 시간 frame. online 시작 전·dependent job 전.
Item = 처리의 최소 단위 (line · row · element).
Logical Unit of Work (LUW) = driving query 또는 input source 의 한 iteration.
Commit Interval = 한 transaction 안에 처리되는 LUW 집합 (= chunk size).
Step·Tasklet
Step = batch 의 메인 task. transaction 환경 + commit interval 제어.
Tasklet = Step 의 비즈니스 로직 component (19편).
입력 패턴
Driving Query = 작업 대상 식별 query (41편 패턴 4).
Staging Table = 처리 중 임시 데이터 보관 테이블 (41편 패턴 변형).
재실행 의미
Restartable = 실패한 동일 JobInstance ID 로 재실행 가능.
Rerunnable = restartable + 이전 run 의 record 상태 자체 관리. 예: Driving Query 의 WHERE processedFlag != true (36편 Process Indicator).
처리 전략
Repeat = 종료 조건까지 반복 호출 (38편).
Retry = 실패한 같은 호출을 같은 input 으로 재시도 (15편·39편).
Recover = 예외 처리 후 repeat 가 계속 진행 가능하게.
Skip = invalid input 무시 (14편).
확장
Partitioning = Job 을 여러 thread/JVM 으로 분할 (37편).
Database 별 schema 변형
MySQL
SEQUENCE미지원 → table +MySQLMaxValueIncrementerengine=InnoDB명시 권장 (transactional)
Oracle
SEQUENCE.NEXTVAL사용- 큰 VARCHAR 는
CLOB권장
PostgreSQL
BIGSERIAL(또는SEQUENCE) 사용JSONB컬럼으로 SERIALIZED_CONTEXT 확장 가능 (custom)
SQL Server
BIGINT IDENTITY또는SEQUENCE- TIMESTAMP →
DATETIME2
H2 (테스트)
- 모든 기능 지원
- 매 시작 schema 자동 초기화 (
initialize-schema: embedded)
각 DB 별 schema 파일은 org/springframework/batch/core/schema-<db>.sql 에 들어있어요.
자주 만나는 사고
사고 1: JobInstance already exists
원인은 같은 JobParameters 로 완료된 JobInstance 가 이미 존재하는 경우예요. 해결책은 21편에서 본 unique parameter (run.id timestamp 등) 를 붙이는 것.
사고 2: STARTED 잔존
원인은 JVM crash · kill -9 · OOM(Out Of Memory, 메모리 부족) 같은 비정상 종료. 해결은 위 SQL 7 (ABANDONED 처리) + JobRepository 정리예요.
사고 3: OptimisticLockingFailureException
원인은 동일 JobExecution 을 여러 process 가 동시에 update 하는 경우. 일반적으로는 batch 동시 실행을 막는 것 으로 해결하고, cluster 환경이라면 leader election 으로 단일 실행자만 두는 게 정석이에요.
사고 4: JOB_KEY 너무 김
원인은 JobParameters 가 많아져서 hash 가 32자를 넘기는 경우. 다행히 JOB_KEY 는 MD5(Message-Digest Algorithm 5, 32자 해시) hash 로 자동 길이가 보장돼요 (Spring Batch 내부 처리).
사고 5: metadata 폭증
원인은 매일 수백 Job 실행이 누적되는 것. 해결은 위 SQL 6 의 주기적 정리 batch — JobRepositoryTestUtils 를 운영용으로 응용해도 좋아요.
사고 6: SERIALIZED_CONTEXT 가 너무 큼
원인은 ExecutionContext 에 복잡한 객체 를 저장한 경우. 24편 권장처럼 단순 type (Long·String 등) 만 넣고 큰 데이터는 별도 테이블 로 빼는 게 맞아요.
사고 7: schema migration 빠뜨림
원인은 Spring Batch 버전 upgrade 시 migration script 를 적용 안 한 경우. 해결은 단순해요 — migration/<version>/ 폴더를 확인하고 적용하는 것.
운영 권장 패턴
Pattern 1: schema 명시 관리
spring:
batch:
jdbc:
initialize-schema: never
운영 DB 는 DBA 가 관리. 자동 schema 생성은 막아둡니다.
Pattern 2: 정기 metadata 정리 Job
@Bean
public Job batchMetadataCleanupJob(JobRepository repo, Step cleanupStep) {
return new JobBuilder("metadataCleanup", repo)
.start(cleanupStep)
.build();
}
@Bean
public Step cleanupStep(JobRepository repo, PlatformTransactionManager tx,
JdbcTemplate jdbc) {
return new StepBuilder("cleanupStep", repo)
.tasklet((contribution, ctx) -> {
// 90일 이상 COMPLETED Job 삭제 (FK 순서)
int deletedContext = jdbc.update("""
DELETE FROM BATCH_STEP_EXECUTION_CONTEXT
WHERE STEP_EXECUTION_ID IN (
SELECT STEP_EXECUTION_ID FROM BATCH_STEP_EXECUTION
WHERE JOB_EXECUTION_ID IN (
SELECT JOB_EXECUTION_ID FROM BATCH_JOB_EXECUTION
WHERE STATUS = 'COMPLETED' AND END_TIME < NOW() - INTERVAL '90 days'
)
)""");
// ... 나머지 테이블도 같은 패턴 ...
return RepeatStatus.FINISHED;
}, tx)
.build();
}
매주 한 번 실행하면 metadata 가 깔끔하게 유지돼요.
Pattern 3: 모니터링 SQL
운영 dashboard 나 Grafana 의 SQL data source 로 직접 query 를 박을 수 있어요.
-- 최근 1시간 Job 실행 통계
SELECT
DATE_TRUNC('hour', START_TIME) AS hour,
STATUS,
COUNT(*) AS count,
AVG(EXTRACT(EPOCH FROM (END_TIME - START_TIME))) AS avg_duration_sec
FROM BATCH_JOB_EXECUTION
WHERE START_TIME > NOW() - INTERVAL '24 hours'
GROUP BY DATE_TRUNC('hour', START_TIME), STATUS
ORDER BY hour DESC;
45편 Micrometer 와 상호 보완 으로 쓰면 좋아요.
Pattern 4: index 추가 (성능)
CREATE INDEX IDX_BATCH_JOB_INSTANCE_NAME ON BATCH_JOB_INSTANCE (JOB_NAME);
CREATE INDEX IDX_BATCH_JOB_EXECUTION_STATUS ON BATCH_JOB_EXECUTION (STATUS);
CREATE INDEX IDX_BATCH_JOB_EXECUTION_START_TIME ON BATCH_JOB_EXECUTION (START_TIME);
CREATE INDEX IDX_BATCH_STEP_EXECUTION_JOB ON BATCH_STEP_EXECUTION (JOB_EXECUTION_ID);
대량 metadata 환경에서는 표준 index 를 추가해주면 운영 SQL 이 훨씬 빨라져요.
Pattern 5: ResourcelessJobRepository (v6 신규)
@Configuration
@EnableJdbcJobRepository
public class BatchConfig {
// ResourcelessJobRepository = DB 없이 in-memory metadata
}
Spring Batch 6 부터 DB 없이 동작하는 in-memory JobRepository 가 들어왔어요. 짧은 batch 나 Spring Cloud Data Flow 환경에서 쓰면 좋고, 단 재시작 안전성은 없다 는 점을 기억해야 해요 — 한 번 실행 후 metadata 가 사라지니까요.
시험 직전 한 번 더 — Meta-Data Schema · Glossary 함정 압축 노트
- 6 테이블 + 3 sequence
BATCH_JOB_INSTANCE= JobInstance (JOB_NAME · JOB_KEY)JOB_KEY= JobParameters 의 hash (instance 식별)BATCH_JOB_EXECUTION= 한 번의 실행 (status · exit_code · start/end_time)STATUS= BatchStatus (COMPLETED · STARTED · FAILED · STOPPED · ABANDONED · UNKNOWN)BATCH_JOB_EXECUTION_PARAMS= parameter 별 row (IDENTIFYINGY/N)IDENTIFYING = Yparameter = JobInstance 식별 기여BATCH_JOB_EXECUTION_CONTEXT·BATCH_STEP_EXECUTION_CONTEXT=SHORT_CONTEXT(JSON) +SERIALIZED_CONTEXT(binary)BATCH_STEP_EXECUTION= step 별 통계 (COMMIT_COUNT · READ_COUNT · FILTER_COUNT · WRITE_COUNT · SKIP_COUNT · ROLLBACK_COUNT)- VERSION 컬럼 = optimistic locking
- 동시 update 충돌 = OptimisticLockingFailureException
- Schema initialization =
spring.batch.jdbc.initialize-schema(always · embedded · never) - 운영 =
never+ DBA 명시 schema - DB 별 schema =
org/springframework/batch/core/schema-<db>.sql - Migration scripts =
migration/<version>/(upgrade 시 적용) - 운영 SQL — 최근 실패 · 비정상 종료 detect · Step 별 통계 · JobInstance 재시도 · JobParameters 검색 · metadata 정리 · STARTED ABANDONED 처리
- ABANDONED 처리 = VERSION 증가 잊지 말 것
JobInstance already exists= 같은 parameter 재실행 (unique run.id)STARTED 잔존= JVM crash → 수동 ABANDONEDOptimisticLockingFailureException= 동시 실행 → leader election- JOB_KEY 길이 = MD5 32자 (자동 보장)
- metadata 폭증 = 정기 정리 batch
- SERIALIZED_CONTEXT 너무 큼 = ExecutionContext 단순 type
- schema migration =
migration/폴더 확인 필수 - Glossary:
- Batch · Batch Window · Item · LUW · Commit Interval
- Step · Tasklet · Driving Query · Staging Table
- Restartable (같은 JobInstance ID) · Rerunnable (자체 상태 관리)
- Repeat (38편) · Retry (15편·39편) · Recover · Skip (14편)
- Partitioning (37편)
- DB 별 변형 — MySQL (table sequence) · Oracle (SEQUENCE.NEXTVAL) · PostgreSQL (BIGSERIAL) · SQL Server (IDENTITY/SEQUENCE) · H2 (embedded)
- ResourcelessJobRepository (Spring Batch 6 신규) = DB 없이 in-memory (재시작 X)
- 패턴 — schema 명시 관리 (never)
- 패턴 — 정기 metadata 정리 batch
- 패턴 — 모니터링 SQL (Grafana data source)
- 패턴 — index 추가 (운영 SQL 성능)
- 패턴 — ResourcelessJobRepository (Spring Cloud Data Flow)
공식 문서: Meta-Data Schema · Glossary 에서 원문을 확인할 수 있어요.
시리즈 다른 편 (앞뒤 글 모음)
이전 글:
- 42편 — Spring Batch Integration · 두 프레임워크 경계
- 43편 — Launching via Messages · JobLaunchingGateway · Informational
- 44편 — Async Processors · Remote Chunking · Partitioning
- 45편 — Observability · Micrometer · Tracing
- 46편 — Java Flight Recorder (JFR) · v6 신규
다음 글: