mybatis ExecutorType Batch Test

구운몽·2023년 1월 29일
0
post-thumbnail

1. 목적과 배경

운영하고 있는 시스템에서 대량 엑셀 업로드가 발생할 경우에 좋지 못한 성능을 보여준다. JPA 관심이 많고 앞으로 mybatis로 개발하는 경우는 거의 없을 것 같지만 미워도 다시 한 번 그리고 운영시스템을 위해서 주말에 잠시 정리해본다.

2. 개발환경

특별할 것 없이 기본 세팅만 한다.

  • spring boot 3.0.2
  • java 17
  • mybatis 3.0.1
  • postgresql 42.2.23
  • lombok

3. 개발내용

- 프로젝트 구조 및 주소

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);
    }
}

- 데이터 Insert

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 + ")");
    }

4. 결과

배치타입과 일반타입(SIMPLE) 모두 10회 씩 100000개의 데이터를 생성하는 로직을 수행시켰다.
배치타입은 1초가 조금 안되는 시간이 걸렸고, 일반적인 경우에는 20초 이상 수행시간을 가졌다.

0개의 댓글