[Spring Batch] Data too long for column ‘SERIALIZED_CONTEXT’
스프링 배치에서는 동일 Job에서 여러 Step에서 공통으로 사용하고 싶은 값이 있으면 ExecutionContext
를 통해 공유가 가능하다.
(ExecutionContext에 대한 내용은 zzang0ha님의 글 참조)
애플리케이션 메모리 위에서는 버틸 수 있는 용량의 값이어도 ExecutionContext
는 그렇지 않을 수 있다.
실제로 너무 많은 값을 저장하려 하는 경우 아래 에러가 발생한다.
org.springframework.dao.DataIntegrityViolationException: PreparedStatementCallback;
SQL [UPDATE BATCH_JOB_EXECUTION_CONTEXT SET SHORT_CONTEXT = ?, SERIALIZED_CONTEXT = ? WHERE JOB_EXECUTION_ID = ?];
Data truncation: Data too long for column 'SERIALIZED_CONTEXT' at row 1;
nested exception is com.mysql.cj.jdbc.exceptions.MysqlDataTruncation:
Data truncation: Data too long for column 'SERIALIZED_CONTEXT' at row 1
이유는 ExecutionContext
에 값을 저장하려고 ExecutionContext#put()
을 호출하면 그 값을 애플리케이션 메모리에 저장하는게
아니고 BATCH_JOB_EXECUTION_CONTEXT이라는 DB 테이블에 저장하기 때문이다.
그렇다보니 수용할 수 없는 크기의 값을 저장하려하면 에러가 발생할 수밖에 없다.
(메모리에 떠있다해도 다음 Step에서 상황에따라 메모리가 터질 수도 있어서 위험하다)
ExecutionContext jobExecutionContext = chunkContext.getStepContext().getStepExecution().getJobExecution().getExecutionContext();
jobExecutionContext.put("commonData", soLongCommonData); // 너무 크면 BATCH_JOB_EXECUTION_CONTEXT에 저장 불가
반드시 값들을 한번에 불러와서 사용해야 하는 상황이라면, 어차피 DB에 있는걸 불러와야 하기때문에 필요한 Step에서 각각 조회하는
방법이 좋다고 생각된다. BATCH_JOB_EXECUTION_CONTEXT
내 컬럼에 우겨 넣는게 안되니까 어쩔 수 없다.
값들을 한번에 불러올 필요가 없고 조금씩 가져와서 처리하는 사이클을 반복해도 된다면, chunk 처리 방식을 사용하는게 좋다.
많은 양의 값을 메모리에 올리는게 아니므로 보다 안전하고 chunk별로 트랜잭션을 지원하기 때문에 트랜잭션이 길어질 염려도 하지
않아도 된다.
댓글남기기