일반적으로 데이터를 추가/수정 할 때, DB 로 SQL 를 전송하기 위해서 매번 네트워크 통신하며 비용을 발생 시킨다.
@Transactional
@Override
public void saveAll(List<Product> products) {
String sql = "insert into product (title, created_ts, price) values (?, ?, ?)";
for (Product product : products) {
this.jdbcTemplate.update(sql,
ps -> {
ps.setString(1, product.getTitle());
ps.setTimestamp(2, Timestamp.valueOf(product.getCreatedTs()));
ps.setBigDecimal(3, product.getPrice());
}
);
}
}
따라서 이러한 많은 량의 데이터(Sql)를 보낼 때 매번 요청을 하나씩 보내는게 아니라 묶어서 처리할 수 있는 Bulk Sql
를 제공한다.
@Transactional
@Override
public void saveAll(List<Product> products) {
String sql = "INSERT INTO product (title, created_ts, price) VALUES (?, ? ,?)";
jdbcTemplate.batchUpdate(sql,
products,
100,
(ps, product) -> {
ps.setString(1, product.getTitle());
ps.setTimestamp(2, Timestamp.valueOf(product.getCreatedTs()));
ps.setBigDecimal(3, product.getPrice());
}
);
}
💡 Bulk Sql 를 사용할 때 전송하는 데이터를 많이 묶는다고 처리 속도가 비례해서 증가하지는 않는다.
또한 Bulk Sql 크기가 큰 경우 해당 로우(테이블) 에 오랜 시간 동안 락이 발생한다는 사실 숙지하고 적절한 크기를 정해야 한다.
아래의 내용을 보면 알 수 있지만 단건과 일괄 처리는 처리해야 하는 데이터가 많을 수록도 더 빠르게 처리하는 것을 확인 할 수 있다. (단건 저장, 일괄 저장)
rewriteBatchedStatements = true 인 경우
spring.datasource.url
에 rewriteBatchedStatements
은 일괄(batch) 처리를 할 수 있도록 해준다.
따라서 DB 일괄 처리가 필요한 경우 반드시 설정할 필요가 있다. (Mysql 에 대한 설정 정보)
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:13306/snow?rewriteBatchedStatements=true
username: snow
password: snow
참고로 rewriteBatchedStatements
속성을 설정을 하지 않는 경우 기본 값으로 false
로 하는 경우 아래와 같이 단건과 동일한 처리율을 보여주는 것을 확인 할 수 있다. (단건 저장, 일괄 저장)
rewriteBatchedStatements = false 인 경우
심플 프로젝트
https://github.com/snowlight-aemt/basic-project-colletion/tree/master/spring-db-batch-performance
일관 처리 프로젝트