Java JDBC Batch 프로그램 sample
JDBC Batch는 프로젝트와 별개로 작업하고 실행을 할 수 있어서 수정사항 발생시 바로바로 적용을 할 수 있다는 점이 운영하는 측에서는 편한 작업이 될 수 있습니다. 그러나 Batch job의 개수가 많아지거나 Table 사이즈가 크거나 작업의 우선 순위가 있어야 하는 경우 등의 상황에서는 다른 방법과 병행해서 사용하는게 개인적으로는 좋았던 것 같습니다.
오늘 기록해 놓으려는 소스는 SELECT 문을 사용해 key값의 데이터가 기존에 입력 되어있는지 확인하고 존재하면 UPDATE, 없으면 INSERT하는 단순 작업입니다.
1. DB 접속
먼저 DB 접속을 정의합니다.
Connection conn = null; Class.forName("org.mariadb.jdbc.Driver"); conn = DriverManager.getConnection("jdbc:mariadb://127.0.0.1:3306", "db_id","db_passwd"); conn.setAutoCommit(false); |
Driver는 사용하는 DB에 맞게 수정하면 됩니다.
2. Select 사용
기존에 입력된 데이터가 있는지 확인을 하기위해 함수를 하나 만들어서 결과를 리턴 받습니다.
int iCnt = getInsertCnt(conn, yesterday);
DB 접속 정보와 날짜를 파라미터로 데이터가 있는지 조회하는 쿼리입니다.
PreparedStatement pstmt = null; int nCnt = 0; ResultSet rs = null; try { StringBuilder sql = new StringBuilder(); sql.append("SELECT count(*) AS CNT FROM test.statistics WHERE INSERT_DT = ?"); pstmt = conn.prepareStatement(sql.toString()); pstmt.setString(1, yesterDay); rs = pstmt.executeQuery(); while(rs.next()) { nCnt = rs.getInt(1); System.out.println("=== CNT : " + rs + "/" + nCnt); } rs.close(); pstmt.close(); } |
PreparedStatement : 쿼리를 높은 효율성으로 반복적으로 사용하기위한 저장 객체.
ResultSet : SQL 쿼리를 실행한 결과를 저장하는 객체.
nCnt : SELECT 결과의 개수를 저장하려고 만든 변수입니다.
쿼리 생성시 사용하는 변수를 물음표(?)로 표시하고 값을 대입해서 쿼리를 완성하게 됩니다.
변수가 변경되면 쿼리는 수정하지 않고 변수 값만 수정해주면 반복해서 쿼리를 사용할 수 있게됩니다.
물음표에 해당하는 값을 대입하는데 사용되는 메소드는 아래처럼 정수, 실수, 문자등을 구분해서 대입하게 됩니다.
public void setInt(int index, int value) public void setString(int index, String value) public void setFloat(int index, float value) public void setDouble(int index, double value) |
index는 물음표의 순번으로 첫번째 물음표는 1이 됩니다.
쿼리를 실행하는 메소드는 여러 종류가 있는데 여기서는 SELECT 결과를 ResultSet에 담아야 하기때문에 리턴 값이 ResultSet인 메소드 executeQuery()를 선택해서 사용했습니다.
좀더 자세한 PreparedStatement 관련 메소드는 아래 링크를 참조하면 도움이 됩니다.
https://docs.oracle.com/javase/8/docs/api/java/sql/Statement.html
JDBC는 업무 로직이 복잡하면 어려워지는거고 실제 사용법은 간단합니다. SELECT문 하나만으로 필요한 내용 설명은 거의 설명이 되는군요.
3. Insert / update
Insert문도 PreparedStatement 와 변수 대입을 위한 setString()을 사용합니다.
PreparedStatement pstmt = null; try { StringBuilder sql = new StringBuilder(); sql.append("INSERT INTO test.statistics ("); sql.append(" INSERT_DT"); sql.append(", VISIT_CNT"); sql.append(", PAGE_VIEW_CNT"); sql.append(", INST_DT"); sql.append(", INST_ID"); sql.append(") VALUES ("); sql.append(" ?"); sql.append(", (select 1 from dual)"); sql.append(", (select 2 from dual)"); sql.append(", date_format(now(), '%Y%m%d%H%i%s')"); sql.append(", 'tester'"); sql.append(")"); pstmt = conn.prepareStatement(sql.toString()); pstmt.setString(1, yesterDay); |
Select에서는 쿼리 실행을 위해 pstmt.executeQuery()를 사용하고 Insert와 Update에서는 addBatch()와 executeBatch()을 사용했습니다.
addBatch()는 쿼리를 바로 실행하지 않고 쿼리 구문을 메모리에 올려두었다가, 실행 명령(executeBatch)이 있으면 한번에 DB쪽으로 쿼리를 보내어 처리를 하게 됩니다. 즉, 한 번의 SQL 수행으로 대량의 로우를 동시에 insert / update / delete를 진행할 수 있어 대용량 처리를 하는데 적합한 방법입니다.
여기서는 달랑 하나 처리했는데 동일한 작업을 진행하려면 loop 문을 이용해서 작업을 하면 됩니다.
간단히 설명이 끝났습니다.
아래 소스를 보면 좀더 파악이 쉬우리라 생각하며 소스를 첨부합니다.
package com.example.demo.test; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.Properties; public class Job { public static void main(String[] args) { Connection conn = null; try { Class.forName("org.mariadb.jdbc.Driver"); conn = DriverManager.getConnection("jdbc:mariadb://127.0.0.1:3306", "root","will99"); conn.setAutoCommit(false); String yesterday = getYesterday(); int iCnt = getInsertCnt(conn, yesterday); if(iCnt < 1) { System.out.println("====== insert =================="); insertData(conn, yesterday); } else { System.out.println("====== update =================="); updateData(conn, yesterday); } conn.close(); } catch (Exception e) { e.printStackTrace(); } finally { if(conn != null) { try { conn.close(); } catch (Exception e) {} } } } private static int getInsertCnt(Connection conn, String yesterDay) { PreparedStatement pstmt = null; int nCnt = 0; ResultSet rs = null; try { StringBuilder sql = new StringBuilder(); sql.append("SELECT count(*) AS CNT FROM test.statistics WHERE INSERT_DT = ?"); pstmt = conn.prepareStatement(sql.toString()); pstmt.setString(1, yesterDay); rs = pstmt.executeQuery(); while(rs.next()) { nCnt = rs.getInt(1); System.out.println("=== CNT : " + rs + "/" + nCnt); } rs.close(); pstmt.close(); } catch (Exception e) { e.printStackTrace(); } finally { if(pstmt != null) { try { pstmt.close(); } catch (Exception e) {} } } return nCnt; } private static void insertData(Connection conn, String yesterDay) { PreparedStatement pstmt = null; try { StringBuilder sql = new StringBuilder(); sql.append("INSERT INTO test.statistics ("); sql.append(" INSERT_DT"); sql.append(", VISIT_CNT"); sql.append(", PAGE_VIEW_CNT"); sql.append(", INST_DT"); sql.append(", INST_ID"); sql.append(") VALUES ("); sql.append(" ?"); sql.append(", (select 1 from dual)"); sql.append(", (select 2 from dual)"); sql.append(", date_format(now(), '%Y%m%d%H%i%s')"); sql.append(", 'tester'"); sql.append(")"); pstmt = conn.prepareStatement(sql.toString()); pstmt.setString(1, yesterDay); pstmt.addBatch(); pstmt.clearParameters(); pstmt.executeBatch(); pstmt.clearBatch(); conn.commit(); pstmt.close(); } catch (Exception e) { e.printStackTrace(); } finally { if(pstmt != null) { try { pstmt.close(); } catch (Exception e) {} } } } private static void updateData(Connection conn, String yesterDay) { PreparedStatement pstmt = null; try { StringBuilder sql = new StringBuilder(); sql.append("UPDATE test.statistics SET "); sql.append("VISIT_CNT = (select 1 from dual)"); sql.append(", PAGE_VIEW_CNT = (select 1 from dual)"); sql.append(", UPDT_DT = date_format(now(), '%Y%m%d%H%i%s')"); sql.append(", UPDT_ID = 'tester'"); sql.append("where INSERT_DT = ?"); pstmt = conn.prepareStatement(sql.toString()); pstmt.setString(1, yesterDay); pstmt.addBatch(); pstmt.clearParameters(); pstmt.executeBatch(); pstmt.clearBatch(); conn.commit(); pstmt.close(); } catch (Exception e) { e.printStackTrace(); } finally { if(pstmt != null) { try { pstmt.close(); } catch (Exception e) {} } } } private static String getYesterday() { Date today = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); String fmDate = sdf.format(today); System.out.println("=== today : " + fmDate); Calendar cal = Calendar.getInstance(); cal.setTime(today); cal.add(Calendar.DATE, -1); String fmDate2 = sdf.format(cal.getTime()); System.out.println("=== yesterday : " + fmDate2); return fmDate2; } } |
- copy coding -