배치 업데이트(Batch Update)란?
INSERT, UPDATE, DELETE처럼 실행 결과로 업데이트 카운트(갱신 건수)를 반환하는 SQL 명령 여러 개를 하나의 그룹으로 묶어 한 번에 실행하는 기법을 배치 업데이트(batch update)라고 합니다.
여기에 매개변수(파라미터)가 포함된 쿼리를 사용해 배치 업데이트를 수행하는 것을 매개변수화된 배치 업데이트(parameterized batch update)라고 부릅니다.
일반적인 배치 업데이트의 동작 방식
일반적인 배치 업데이트는 addBatch() 메서드로 실행할 문장들을 모두 추가한 뒤, executeBatch() 메서드로 한 번에 실행하는 방식으로 처리합니다.
// Statement 객체 생성
Statement stmt = con.createStatement();
// 자동 커밋 비활성화
con.setAutoCommit(false);
// 배치에 문장 추가
stmt.addBatch("INSERT INTO Sales VALUES ('KeyBoard', 'Amith', 'January', 1000, 'Hyderabad')");
stmt.addBatch("INSERT INTO Sales VALUES ('Earphones', 'SUMITH', 'March', 500, 'Vishakhapatnam')");
stmt.addBatch("INSERT INTO Sales VALUES ('Mouse', 'Sudha', 'September', 200, 'Vijayawada')");
// 배치 실행
stmt.executeBatch();
그런데 위 코드를 잘 살펴보면 INSERT 문의 대부분이 반복되고 값의 일부만 달라지는 것을 확인할 수 있습니다. 이런 경우에는 매번 전체 쿼리 문자열을 작성하는 대신, 플레이스홀더(?)를 사용한 PreparedStatement를 활용하는 것이 훨씬 효율적입니다. setter 메서드로 값만 교체해 가면서 배치에 추가하면 되기 때문입니다.
매개변수화된 배치 업데이트 작성 방법
매개변수화된 배치 업데이트는 다음 순서로 작성합니다.
- 플레이스홀더(?)가 포함된 INSERT, UPDATE 또는 DELETE 쿼리로
PreparedStatement객체를 생성합니다. setXXX()계열 메서드(setString(), setInt() 등)를 사용해 각 플레이스홀더에 값을 설정합니다.addBatch()메서드로 해당 값 세트를 배치에 추가합니다.- 모든 값 세트를 추가한 후
executeBatch()메서드로 배치를 한 번에 실행합니다.
주의: 배치에 문장을 추가하기 전에 반드시 con.setAutoCommit(false)로 자동 커밋을 비활성화해야 하며, 배치 실행 후에는 con.commit() 메서드를 호출해 변경 사항을 저장(커밋)해야 합니다.
예제
데이터베이스에 다음과 같은 구조의 Sales 테이블이 생성되어 있다고 가정해 보겠습니다.
+-------------------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------------------+--------------+------+-----+---------+-------+ | Product_Name | varchar(255) | YES | | NULL | | | Name_Of_Customer | varchar(255) | YES | | NULL | | | Month_Of_Dispatch | varchar(255) | YES | | NULL | | | Price | int(11) | YES | | NULL | | | Location | varchar(255) | YES | | NULL | | +-------------------+--------------+------+-----+---------+-------+
아래 예제는 매개변수화된 배치 업데이트를 사용해 위 테이블에 여러 건의 레코드를 한 번에 삽입하는 프로그램입니다.
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.Statement;
public class ParameterizedBatchUpdate {
public static void main(String args[])throws Exception {
// 데이터베이스 연결
String mysqlUrl = "jdbc:mysql://localhost/testDB";
Connection con = DriverManager.getConnection(mysqlUrl, "root", "password");
System.out.println("Connection established......");
// 자동 커밋 비활성화
con.setAutoCommit(false);
// 플레이스홀더를 사용한 PreparedStatement 생성
PreparedStatement pstmt = con.prepareStatement("INSERT INTO Sales VALUES (?, ?, ?, ?, ?)");
// 첫 번째 레코드 설정 및 배치 추가
pstmt.setString(1, "KeyBoard");
pstmt.setString(2, "Amith");
pstmt.setString(3, "January");
pstmt.setInt(4, 1000);
pstmt.setString(5, "Hyderabad");
pstmt.addBatch();
// 두 번째 레코드 설정 및 배치 추가
pstmt.setString(1, "Earphones");
pstmt.setString(2, "Sumith");
pstmt.setString(3, "March");
pstmt.setInt(4, 500);
pstmt.setString(5, "Vishakhapatnam");
pstmt.addBatch();
// 세 번째 레코드 설정 및 배치 추가
pstmt.setString(1, "Mouse");
pstmt.setString(2, "Sudha");
pstmt.setString(3, "September");
pstmt.setInt(4, 500);
pstmt.setString(5, "Vishakhapatnam");
pstmt.addBatch();
// 배치 실행
pstmt.executeBatch();
// 변경 사항 저장
con.commit();
System.out.println("Records inserted......");
}
}
실행 결과
Connection established...... Records inserted......
이처럼 매개변수화된 배치 업데이트를 활용하면 쿼리 문자열의 중복을 없애고, 값만 교체해 가며 대량의 데이터를 효율적으로 처리할 수 있습니다. 또한 PreparedStatement는 SQL 인젝션 방지와 성능 최적화 측면에서도 유리하기 때문에 실무에서 권장되는 방식입니다.