jdbcTemplate.batchUpdate()로 batch insert 하기

January 01, 2021

Spring Data JPA의 saveAll은 인자 값으로 받은 entity들을 저장하는 메서드이다. 실제로 실행해보면 정상적으로 작동하는 것을 확인할 수 있지만, 로그를 보면 하나씩 insert 하는 것을 확인할 수 있다.

val items = (1..1000).map { Item(name = "피자", amount = 10000) }
val measureTimeMillis = measureTimeMillis{ itemRepository.saveAll(items) }
println("실행시간 $measureTimeMillis")

saveAll 실행 결과

이를 해결하기 위한 방법들도 존재하지만, entity의 id값의 결정을 db에 위임하기 위해 @GeneratedValue(strategy = GenerationType.IDENTITY)로 정의했다면 사용할 수 없다. 따라서 이러한 상황에서 매우 많은 양의 데이터를 한번에 저장할 때 saveAll을 사용하는 것은 시스템의 성능 저하를 야기할 수 있기 때문에 주의해야한다.

기존의 entity id 생성 전략을 바꾸는 것은 쉽게 결정할 일이 아니기 때문에 이러한 상황에서 batch insert를 수행하기 위해서 jdbcTemplatebatchUpdate를 사용할 수 있다.

override fun batchInsert(items: List<Item>) {
    jdbcTemplate.batchUpdate("insert into item (name, amount) values (?, ?)",
        items,
        100,
        object : ParameterizedPreparedStatementSetter<Item?> {
            override fun setValues(ps: PreparedStatement, argument: Item) {
                ps.setString(1, argument.getName())
                ps.setInt(2, argument.getAmount())
            }
        })
}

batchUpdate 메서드에서 첫 번째 인자로 query, 두 번째 인자로 저장할 데이터의 collection, 세 번째 인자로 batch 처리할 크기, 마지막으로 ParameterizedPreparedStatementSetter를 해주면 된다. ParameterizedPreparedStatementSetter에서 db table에 저장 될 각 column의 내용을 지정해주면 된다.

fun batchInsert(items: List<Item>) {
        jdbcTemplate.batchUpdate(
            "insert into item (name, amount) values (?, ?)", items, 100
        ) { ps, argument ->
            ps.setString(1, argument.getName())
            ps.setInt(2, argument.getAmount())
        }
}

lambda expression으로 나타내면 위와 같이 표현할 수도 있다.

여기서 주의할 점은
mysql jdbc의 경우 jdbc url에rewriteBatchedStatements=true 옵션을 추가한다. 해당 옵션을 추가하지 않으면 batch insert가 실행되지 않는다.

그리고 mysql에서 실제로 처리되는 쿼리를 확인하기 위해 profileSQL=true&logger=Slf4JLogger 추가한다.

batchInsert 실행 결과

실행결과를 보면 앞서 수행한 saveAll보다 빠른 219 ms에 실행된 것을 확인할 수 있으며, 실제 쿼리도 batch insert 형태로 처리한 것을 확인할 수 있다.
여기서 1000개의 entity를 저장하기 위해 100개씩 저장되는 batch insert가 10번 실행된다.

예제코드는 https://github.com/pss89513/batch-insert-example 에서 확인할 수 있다.


참고문서


Hello, world!