목적
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 |