문제 인식
- Spring Batch에서
slave
DB에서 SELECT
쿼리 수행 후, master
로 INSERT
작업을 하는 구조에서,
slave 커넥션이 반환되지 않아 커넥션 풀 고갈 발생 가능
- 특히, MyBatis + Spring 트랜잭션 환경에서는 커넥션 반환 타이밍이 복잡하게 엮임
- HikariCP의
auto-commit=true
설정에도 불구하고, 커넥션이 즉시 반환되지 않음
핵심 원인
auto-commit=true
는 JDBC 레벨의 기본 동작일 뿐
- MyBatis는 내부적으로 트랜잭션처럼 동작하며,
SqlSessionTemplate
이 커넥션을 유지
- Spring 트랜잭션이 시작되면
setAutoCommit(false)
가 적용되어 반환 시점이 명시적 트랜잭션 종료 시점으로 지연됨
해결 방법
1. TransactionTemplate
으로 slave 트랜잭션 분리
List<Data> list = slaveTxSupport.read(() -> slaveMapper.selectByCondition(paramA, paramB));
readOnly=true
설정으로 성능 최적화
- 쿼리 실행 후 트랜잭션 자동 종료 → 커넥션 즉시 반환
2. chunk 방식에서 ListItemReader에 적용 가능
@Bean
@StepScope
public ListItemReader<Entity> reader() {
return new ListItemReader<>(
slaveTxSupport.read(() -> mapper.selectList(param))
);
}
- chunk 트랜잭션 시작 전에 slave 쿼리 처리 → 안전하게 분리됨
3. 커넥션 반환 여부 확인
HikariPoolMXBean
을 통해 JConsole
이나 VisualVM
으로 확인 가능
- 또는
datasource-proxy
를 사용해 커넥션 획득/반환 로그 확인 가능
leak-detection-threshold
설정 시 누수 경고도 감지 가능
MyBatis Interceptor에서 커넥션 직접 반환은?
- Spring 환경에서는 비권장
- Spring의
TransactionSynchronizationManager
와 충돌할 수 있음
- 커넥션은 트랜잭션 종료 후 Spring이 관리하는 흐름에 맡기는 것이 가장 안전함
결론
slave
DB 조회는 TransactionTemplate
으로 read-only 트랜잭션을 분리하자
master
쓰기는 Step 트랜잭션에 맡기고, 구조는 명확하게 분리
- Hikari 커넥션 풀 모니터링도 설정해서 커넥션 누수 감지를 강화하자