JdbcTemplate에서 batchUpdate() 사용하는 주 목적은 성능이다.
내가 주로 사용하고 있는 JPA saveAll()은 대체로 작은 데이터셋에서는 사용에 적합하다. 엔티티를 관리하는데 드는 비용이 크기 때문에 큰 데이터셋을 처리할 때는 성능 문제가 발생할 수 있다.
batchUpdate()는 사용하여 원시 SQL을 사용하여 엔티티를 사용하는 JPA보다 더 낮은 오버헤드를 제공한다. 따라서 성능이 매우 높고, 대규모 데이터를 처리할 때 JPA보다 더 적합하다.

10만건을 기준으로 처리 시간 차이이다. 테이블 인덱스나 데이터양의 차이에 따라 JPA는 시간적으로 편차가있으나 JdbcTemplate의 속도에 미치지 못한다.
@Transactional
public Object batchUpdate(String userId, Request request) {
String sql = " UPDATE central_cities SET is_central = ?, modified = GETDATE(), modified_by = ? " +
" WHERE country_id = ? AND city_id = ?";
int[][] updateCounts;
try {
updateCounts = this.jdbcTemplate.batchUpdate(sql, request.getCities(), 100, (ps, city) -> {
ps.setBoolean(1, city.getIsCentral());
ps.setString(2, userId);
ps.setString(3, city.getCountryId());
ps.setString(4, city.getCityId());
});
} catch (Exception e) {
throw new RuntimeException("Failed to update cities: " + e.getMessage(), e);
}
// 성공 결과 반환
Map<String, Object> result = new HashMap<>();
result.put("totalUpdates", updateCounts.length);
result.put("success", Arrays.stream(updateCounts).findAny().isPresent());
return result;
}
@Getter
public class Request {
private List<City> cities;
@Getter
public static class City {
private String countryId;
private String cityId;
private Boolean isCentral;
}
}

SQL문을 한 번만 파싱하고 재사용한다.
-- PreparedStatement가 내부적으로 처리하는 방식
PREPARE stmt FROM 'UPDATE central_cities SET is_central = ?, modified = GETDATE(), modified_by = ? WHERE country_id = ? AND city_id = ?';
-- 배치로 파라미터 바인딩 후 실행
EXECUTE stmt USING true, 'admin001', 'KR', 'SEOUL';
EXECUTE stmt USING false, 'admin001', 'KR', 'BUSAN';
-- ... 100개 실행
DEALLOCATE PREPARE stmt;
예시는 Update를 다뤘지만 Insert, Delete에 대해서도 가능하다.
-- JPA saveAll
INSERT INTO central_cities VALUES ('KR', 'SEOUL', true, GETDATE(), 'admin001');
INSERT INTO central_cities VALUES ('KR', 'BUSAN', false, GETDATE(), 'admin001');
-- Batch Insert
INSERT INTO central_cities VALUES
('KR', 'SEOUL', true, GETDATE(), 'admin001'),
('KR', 'BUSAN', false, GETDATE(), 'admin001')
SQL의 Batch Insert를 Spring에서 사용한다고 보면된다.
JPA를 주로 사용한 프로젝트에서 대용량 데이터가 다루는 부분에서는 사용을 고려해볼만하다.