목적
Batch Processing? - wiki
- 많은 사용자 사이에서 컴퓨터 자원을 공유할 수 있다.
- 작업 프로세스의 시간대를 컴퓨터 리소스가 덜 사용되는 시간대로 이동한다.
- 분 단위의 사용자 응답 대기와 더불어 컴퓨터 리소스의 유휴 사용을 피한다.
- 전반적인 이용률을 높임으로써 컴퓨터의 비용을 더 잘 상환하도록 도와 준다.
JDBC에서 Batch Processing
preparedStatement를 사용한 Batch Processing
PreparedStatement stmt = conn.prepareStatement( "UPDATE account SET balance = ? WHERE acct_id = ?");"UPDATE account SET balance = ? WHERE acct_id = ?"); int[] rows; for(int i=0; i<accts.length; i++) { accts[i].calculateInterest( ); stmt.setDouble(1, accts[i].getBalance( )); stmt.setLong(2, accts[i].getID( )); stmt.addBatch( ); } rows = stmt.executeBatch( );
- addBatch() : create, insert, update, deleted 일괄 처리 결과를 관리 할 필요가 없기 때문에 batch에 statement를 추가하는 일만 한다.
- excuteBatch()가 쿼리들을 수행하고 정수형 배열을 리턴하는데, 각 배열의 요소는 각 statement로 인해 update된 row의 숫자이다.
Mybatis Batch Mode
Mybatis는 SqlSessionFactory에서 SqlSessionTemplate(SqlSession 구현체)을 생성할 때 ExcutorType을 지정해 줄 수 있다.
ExcutorType | Description |
---|---|
SIMPLE | executor does nothing special |
REUSE | executor reuses prepared statements |
BATCH | executor reuses statements and batches updates |
ExecutorType.BATCH : 이 실행자는 모든 update(C,I,U,D)구문을 배치처리하고 중간에 select 가 실행될 경우 필요하다면 경계를 표시한다.
여기서 이 경계는 아래 소스코드를 통해 확인 할 수 있다.
SqlSessionTemplate에서 ExecutorType이 BATCH인 경우에 Create, Insert, Update, Delete 구문은 doUpdate 에서, Select 구문은 doQuery 에서 처리한다.
아래 코드의 59번 줄에서 statement를 재사용하는 로직을 확인 할 수 있고, 61번, 69번 줄에서 statement 재사용 여부에 따라 statementList에 statement를 추가하고 63번, 70번 줄에서 파라미터 추가, 다른 구문일 경우 BatchResult를 추가하는 것을 볼 수 있다.
그리고 doQuery 메소드의 81번줄에서 flushStatements()를 호출 하는데, 이는 그동안 statementList에 쌓아 왔던 statement를 executeBatch() 메소드로 수행한다. 수행 결과는 batchResult에 저장하여 return 하고, 그동안 쌓아왔던 statementList 와 batchResultList 를 초기화한다.
아래 코드처럼 Select문이 실행 될 경우 BATCH 처리를 멈추고 초기화 하기 때문에, BATCH 작업 도중 SELECT 문이 끼어들면 성능이 저하된다.
org.apache.ibatis.executor.BatchExecutor.class - grepcode
40 public class More ...BatchExecutor extends BaseExecutor { 41 42 public static final int BATCH_UPDATE_RETURN_VALUE = Integer.MIN_VALUE + 1002; 43 44 private final List<Statement> statementList = new ArrayList<Statement>(); 45 private final List<BatchResult> batchResultList = new ArrayList<BatchResult>(); 46 private String currentSql; 47 private MappedStatement currentStatement; 48 49 public More ...BatchExecutor(Configuration configuration, Transaction transaction) { 50 super(configuration, transaction); 51 } 52 53 public int More ...doUpdate(MappedStatement ms, Object parameterObject) throws SQLException { 54 final Configuration configuration = ms.getConfiguration(); 55 final StatementHandler handler = configuration.newStatementHandler(this, ms, parameterObject, RowBounds.DEFAULT, null, null); 56 final BoundSql boundSql = handler.getBoundSql(); 57 final String sql = boundSql.getSql(); 58 final Statement stmt; 59 if (sql.equals(currentSql) && ms.equals(currentStatement)) { 60 int last = statementList.size() - 1; 61 stmt = statementList.get(last); 62 BatchResult batchResult = batchResultList.get(last); 63 batchResult.addParameterObject(parameterObject); 64 } else { 65 Connection connection = getConnection(ms.getStatementLog()); 66 stmt = handler.prepare(connection); 67 currentSql = sql; 68 currentStatement = ms; 69 statementList.add(stmt); 70 batchResultList.add(new BatchResult(ms, sql, parameterObject)); 71 } 72 handler.parameterize(stmt); 73 handler.batch(stmt); 74 return BATCH_UPDATE_RETURN_VALUE; 75 } 76 77 public <E> List<E> More ...doQuery(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) 78 throws SQLException { 79 Statement stmt = null; 80 try { 81 flushStatements(); 82 Configuration configuration = ms.getConfiguration(); 83 StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameterObject, rowBounds, resultHandler, boundSql); 84 Connection connection = getConnection(ms.getStatementLog()); 85 stmt = handler.prepare(connection); 86 handler.parameterize(stmt); 87 return handler.<E>query(stmt, resultHandler); 88 } finally { 89 closeStatement(stmt); 90 } 91 } 92 93 public List<BatchResult> More ...doFlushStatements(boolean isRollback) throws SQLException { 94 try { 95 List<BatchResult> results = new ArrayList<BatchResult>(); 96 if (isRollback) { 97 return Collections.emptyList(); 98 } else { 99 for (int i = 0, n = statementList.size(); i < n; i++) { 100 Statement stmt = statementList.get(i); 101 BatchResult batchResult = batchResultList.get(i); 102 try { 103 batchResult.setUpdateCounts(stmt.executeBatch()); 104 MappedStatement ms = batchResult.getMappedStatement(); 105 List<Object> parameterObjects = batchResult.getParameterObjects(); 106 KeyGenerator keyGenerator = ms.getKeyGenerator(); 107 if (Jdbc3KeyGenerator.class.equals(keyGenerator.getClass())) { 108 Jdbc3KeyGenerator jdbc3KeyGenerator = (Jdbc3KeyGenerator) keyGenerator; 109 jdbc3KeyGenerator.processBatch(ms, stmt, parameterObjects); 110 } else if (!NoKeyGenerator.class.equals(keyGenerator.getClass())) { //issue #141 111 for (Object parameter : parameterObjects) { 112 keyGenerator.processAfter(this, ms, stmt, parameter); 113 } 114 } 115 } catch (BatchUpdateException e) { 116 StringBuffer message = new StringBuffer(); 117 message.append(batchResult.getMappedStatement().getId()) 118 .append(" (batch index #") 119 .append(i + 1) 120 .append(")") 121 .append(" failed."); 122 if (i > 0) { 123 message.append(" ") 124 .append(i) 125 .append(" prior sub executor(s) completed successfully, but will be rolled back."); 126 } 127 throw new BatchExecutorException(message.toString(), e, results, batchResult); 128 } 129 results.add(batchResult); 130 } 131 return results; 132 } 133 } finally { 134 for (Statement stmt : statementList) { 135 closeStatement(stmt); 136 } 137 currentSql = null; 138 statementList.clear(); 139 batchResultList.clear(); 140 } 141 } 142 143}
기타, 참조
용어
Batch Processing - https://ko.wikipedia.org/wiki/%EC%9D%BC%EA%B4%84_%EC%B2%98%EB%A6%AC
Batch Processing(JDBC) - https://www.safaribooksonline.com/library/view/database-programming-with/1565926161/ch04s02.html
Batch Processing(JDBC) - http://www.tutorialspoint.com/jdbc/jdbc-batch-processing.htm
Mybatis3 - http://www.mybatis.org/mybatis-3/ko/index.html
Grep Code(org.apache.ibatis.executor.BatchExecutor.class) - http://grepcode.com/file/repo1.maven.org/maven2/org.mybatis/mybatis/3.2.7/org/apache/ibatis/executor/BatchExecutor.java#BatchExecutor
'DATA' 카테고리의 다른 글
[애자일로 빅픽처를 그리다] 데이터 대시보드 #2 (1405) | 2022.03.11 |
---|---|
[애자일로 빅픽처를 그리다] 데이터 대시보드 feat. GA4 (1360) | 2022.03.11 |
Flyway 개념 & 사용법 (519) | 2015.11.05 |