운영하고 있는 시스템에서 대량 엑셀 업로드가 발생할 경우에 좋지 못한 성능을 보여준다. JPA 관심이 많고 앞으로 mybatis로 개발하는 경우는 거의 없을 것 같지만 미워도 다시 한 번 그리고 운영시스템을 위해서 주말에 잠시 정리해본다.
특별할 것 없이 기본 세팅만 한다.
https://github.com/egoomoy/Mybatis-ExecutorType-Batch
sqlSessionTemplate을 ExecutorType defualt(SIMPLE)와 BATCH로 구분해서 생성한다. 기본적으로 스프링 부트는 mybasit config를 작성(SqlSessionFactory 등의 설정)하지 않더라도 mybatis-spring-boot-starter를 통해서 제공되는 듯하다. 다만 이번 예제에서는 BATCH 타입을 사용하는 SqlSessionTemplate가 필요하여 수동으로 추가 설정했다.
@Configuration
public class MyBatisConfig {
@Bean(name = "dataSource")
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
..... 생략 .....
@Bean(name = "sqlSessionTemplate")
@Primary
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
@Bean(name = "batchSqlSessionTemplate")
public SqlSessionTemplate batchSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory, ExecutorType.BATCH);
}
}
batch 입력은 List로 모아 넘겨서 실행해주었다.
@Override
@Transactional
public void batchInsertDummies() throws Exception {
log.info("batchSqlSession 배치 테스트 시작");
long startTime = System.currentTimeMillis();
String[] nameArr = {"Alero", "Ed", "Kathryn", "Prea", "Sean", "Peter", "spam", "bungee", "swallow", "eht"};
String[] genderArr = {"M", "F", "N"};
int cycleCount = 10;
int oneOfCycle = 100000;
for (int i = 0; i < cycleCount; i++) {
List<Dummy> dummies = new ArrayList<Dummy>();
for (int j = 0; j < oneOfCycle; j++) {
Dummy dm = new Dummy();
dm.setGender(genderArr[(int) (Math.random() * 3)]);
dm.setName(nameArr[(int) (Math.random() * 10)]);
dummies.add(dm);
}
testDao.insertDummies(dummies);
}
long endTime = System.currentTimeMillis();
long resultTime = endTime - startTime;
log.info("batchSqlSession 배치 테스트 종료");
log.info("batchSqlSession 배치" + " 소요시간 : " + resultTime / 1000 + "초(" + resultTime + ")");
}
@Override
@Transactional
public void foreachInsertDummies() throws Exception {
log.info("foreach 배치 테스트 시작");
long startTime = System.currentTimeMillis();
String[] nameArr = {"Alero", "Ed", "Kathryn", "Prea", "Sean", "Peter", "spam", "bungee", "swallow", "eht"};
String[] genderArr = {"M", "F", "N"};
int cycleCount = 10;
int oneOfCycle = 100000;
for (int i = 0; i < cycleCount; i++) {
for (int j = 0; j < oneOfCycle; j++) {
Dummy dm = new Dummy();
dm.setGender(genderArr[(int) (Math.random() * 3)]);
dm.setName(nameArr[(int) (Math.random() * 10)]);
testDao.insertDummy(dm);
}
}
long endTime = System.currentTimeMillis();
long resultTime = endTime - startTime;
log.info("foreach 배치 테스트 종료");
log.info("foreach 배치" + " 소요시간 : " + resultTime / 1000 + "초(" + resultTime + ")");
}
배치타입과 일반타입(SIMPLE) 모두 10회 씩 100000개의 데이터를 생성하는 로직을 수행시켰다.
배치타입은 1초가 조금 안되는 시간이 걸렸고, 일반적인 경우에는 20초 이상 수행시간을 가졌다.