[java] 대량 데이터 나눠서 저장하기 (Chunk) By starseat 2023-09-21 13:39:25 java/spring Post Tags # 계기 대량 데이터를 나눠서 저장해야 되는 일이 생겼다. 단순한 `Insert` 이기에 크게 신경 안쓰고 개발 하였는데 아래와 같은 오류가 발생 하였다. ```text Cause: java.sql.BatchUpdateException: (conn=313085) query size (4194304) is >= to max_allowed_packet (4194304) ``` 데이터 사이즈가 query size 인 약 4 Mb 보다 크다는 것이다. 이 `max_allowed_packet` 는 서버로 질의하거나 받는 패킷의 최대 길이이다. 참고로 DB 에 접속하여 아래 명령어로 확인 가능하다. ```sql SHOW VARIABLES LIKE 'max%'; ``` 문제는 대량 데이터를 안전하게 저장해야 되는데 이런 이슈가 나서 데이터를 나눠서 저장하는 로직을 구현했다. (보통 청크(Chunk) 단위로 부른다.) # 구현 대단한 로직은 아니지만 나중에 머리를 다시 쓰기 싫기도 하고, 도움이 되는 사람이 있을까 싶어 남긴다. ```java // int MAX_INSERT_ITEM_SIZE = 10000; // 1 만 단위라고 가정. public void saveAll(List list) { int itemSize = list.size(); log.info("[saveAll] data size: {}", itemSize); int lastIndex = (itemSize + MAX_INSERT_ITEM_SIZE - 1) / MAX_INSERT_ITEM_SIZE; for (int index = 0; index < lastIndex; index++) { int fromIndex = index * MAX_INSERT_ITEM_SIZE; int toIndex = Math.min((index + 1) * MAX_INSERT_ITEM_SIZE, itemSize); repository.saveAll(list.subList(fromIndex, toIndex)); log.info("[saveAll] ({}/{}) inserted data. from: {}, to: {}", (index+1), lastIndex, fromIndex, toIndex); } } ``` # 추가 구현을 하고 테스트를 하니 아래와 같은 `Connection Timeout` 이 났는데 ```text org.springframework.jdbc.UncategorizedSQLException: {xxx.package} (batch index #1) failed. Cause: java.sql.BatchUpdateException: (conn=94767) Communications link failure with primary host {jdbc-url}. Connection timed out ; uncategorized SQLException; SQL state [25S03]; error code [0]; (conn=94767) Communications link failure with primary host {jdbc-url}. Connection timed out; nested exception is java.sql.BatchUpdateException: (conn=94767) Communications link failure with primary host {jdbc-url}. Connection timed out ``` 이 부분은 jdbc 설정에서 아래 옵션을 추가 하였다. ```text socketTimeout=0 ``` ```text datasource: jdbc-url: {jdbc-url}?rewriteBatchedStatements=true&socketTimeout=0 ``` Previous Post [spring] jacoco 테스트 항목 제외하기 Next Post [SpotBugs] might be used to include CRLF characters into log messages