2018. 12. 18. 00:13ㆍSpring Batch
Range Partitioning 구현
앞에서 설정한 설정 정보를 이용하여 실제로 예제를 구현해보도록 하자. 입력 데이터는 MySQL 테이블에 등록 해두었고 이 데이터를 Oracle 테이블에 등록 해보도록 하자.
구현에 앞서 프로그램 전체적인 구조는 아래 그림을 참고 하도록 하자.
- 전체적인 구조는 사용자가 지정한 grid-size 만큼 작업을 분할한다. 예제에서는 5로 설정 하였다. 따라서 위의
그림을 보면 5개의 Slave가 생성된다.
- 앞에서 작성한 ColumnRangePartitioner 클래스를 이용하여서 minValue와 maxValue를 구한다.
- 그리고 Slave 별로 Reader, Writer 작업을 수행한다.
RangePartitionJob.xml 작성
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/batch
http://www.springframework.org/schema/batch/spring-batch.xsd">
<description>
<![CDATA[
이 예제는 대용량 데이터 처리 시 작업을 분할 하여 처리하는 Partitioner 예제이다.
]]>
</description>
<job id="rangePartitionJob" xmlns="http://www.springframework.org/schema/batch">
<step id="rangePartitionStep">
<!-- slave -->
<partition step="masterRangePartition" partitioner="rangePartioner">
<handler grid-size="5" task-executor="taskExecutor"/>
</partition>
</step>
</job>
<!-- Column Partition 설정 -->
<bean id="rangePartioner" class="com.batchguide.partitioner.ColumnRangePartitioner">
<property name="dataSource" ref="mysqlDataSource" />
<property name="table" value="black_friday" />
<property name="column" value="user_id" />
</bean>
<bean id="taskExecutor" class="org.springframework.core.task.SimpleAsyncTaskExecutor" />
<!-- READER, WIRTER 설정 -->
<step id="masterRangePartition" xmlns="http://www.springframework.org/schema/batch">
<tasklet>
<chunk writer="blackFridayWriter" reader="blackFridayReader" commit-interval="1000" />
</tasklet>
</step>
<!-- Reader 설정 -->
<bean id="blackFridayReader" class="org.mybatis.spring.batch.MyBatisCursorItemReader" scope="step">
<!-- queryId 설정 -->
<property name="queryId" value="selectBlackFridays" />
<!-- parameters 설정 -->
<property name="parameterValues">
<map>
<entry key="minId" value="#{stepExecutionContext[minValue]}"/>
<entry key="maxId" value="#{stepExecutionContext[maxValue]}"/>
</map>
</property>
<!-- sqlSession -->
<property name="sqlSessionFactory" ref="mysqlSqlSession" />
</bean>
<!-- Writer 설정 -->
<bean id="blackFridayWriter" class="org.mybatis.spring.batch.MyBatisBatchItemWriter">
<property name="statementId" value="insertBlackFridayForOracle" />
<property name="sqlSessionTemplate" ref="batchOracleSqlSessionTemplate" />
</bean>
</beans>
- 분할할 작업수를 grid-size를 통해서 설정한다.
- 분할정보를 설정하기 위해 데이터소스, 테이블명, 컬럼명을 ColumnRangePartitioner 에 전달
- 분할된 정보를 이용하여 Reader/Writer 작업 수행
blackFridayReader 작성
MySQLQuery.xml 파일에 아래 쿼리를 작성한다.
파라미터정보는 minId, maxId를 넘겨주는데 이 값은 ColumnRangePartitioner에서 구한 minValue와 maxValue이다.
<select id="selectBlackFridays" resultType="com.batchguide.vo.BlackFridayVO">
<![CDATA[
select /* id:selectBlackFridays| BlackFriday 데이터 조회 | MySQLQuerySQL.xml */
user_id
, product_id
, gender
, age
, occupation
, city_category
, stay_in_current_city_years
, marital_status
, product_category_1
, product_category_2
, product_category_3
, purchase
from black_friday
where user_id >= #{minId} and user_id <= #{maxId}
]]>
</select>
blackFridayWriter 작성
OracleSQLQuery.xml 파일에 아래 쿼리를 작성한다.
<insert id="insertBlackFridayForOracle" parameterType="com.batchguide.vo.BlackFridayVO">
insert /* id:insertBlackFridayForOracle| BlackFriday 데이터 저장 | MySQLQuerySQL.xml */
into black_friday
(user_id
, product_id
, gender
, age
, occupation
, city_category
, stay_in_current_city_years
, marital_status
, product_category_1
, product_category_2
, product_category_3
, purchase)
values (#{userId}
, #{productId}
, #{gender}
, #{age}
, #{occupation}
, #{cityCategory}
, #{stayInCurrentCityYears}
, #{maritalStatus}
, #{productCategory1}
, #{productCategory2}
, #{productCategory3}
, #{purchase})
</insert>
BlackFridayVO 작성
조회결과는 담는 클래스
package com.batchguide.vo;
public class BlackFridayVO {
private String userId;
private String productId;
private String gender;
private String age;
private String occupation;
private String cityCategory;
private String stayInCurrentCityYears;
private String maritalStatus;
private String productCategory1;
private String productCategory2;
private String productCategory3;
private String purchase;
/**
* @return the userId
*/
public String getUserId() {
return userId;
}
/**
* @param userId the userId to set
*/
public void setUserId(String userId) {
this.userId = userId;
}
/**
* @return the productId
*/
public String getProductId() {
return productId;
}
/**
* @param productId the productId to set
*/
public void setProductId(String productId) {
this.productId = productId;
}
/**
* @return the gender
*/
public String getGender() {
return gender;
}
/**
* @param gender the gender to set
*/
public void setGender(String gender) {
this.gender = gender;
}
/**
* @return the age
*/
public String getAge() {
return age;
}
/**
* @param age the age to set
*/
public void setAge(String age) {
this.age = age;
}
/**
* @return the occupation
*/
public String getOccupation() {
return occupation;
}
/**
* @param occupation the occupation to set
*/
public void setOccupation(String occupation) {
this.occupation = occupation;
}
/**
* @return the cityCategory
*/
public String getCityCategory() {
return cityCategory;
}
/**
* @param cityCategory the cityCategory to set
*/
public void setCityCategory(String cityCategory) {
this.cityCategory = cityCategory;
}
/**
* @return the stayInCurrentCityYears
*/
public String getStayInCurrentCityYears() {
return stayInCurrentCityYears;
}
/**
* @param stayInCurrentCityYears the stayInCurrentCityYears to set
*/
public void setStayInCurrentCityYears(String stayInCurrentCityYears) {
this.stayInCurrentCityYears = stayInCurrentCityYears;
}
/**
* @return the maritalStatus
*/
public String getMaritalStatus() {
return maritalStatus;
}
/**
* @param maritalStatus the maritalStatus to set
*/
public void setMaritalStatus(String maritalStatus) {
this.maritalStatus = maritalStatus;
}
/**
* @return the productCategory1
*/
public String getProductCategory1() {
return productCategory1;
}
/**
* @param productCategory1 the productCategory1 to set
*/
public void setProductCategory1(String productCategory1) {
this.productCategory1 = productCategory1;
}
/**
* @return the productCategory2
*/
public String getProductCategory2() {
return productCategory2;
}
/**
* @param productCategory2 the productCategory2 to set
*/
public void setProductCategory2(String productCategory2) {
this.productCategory2 = productCategory2;
}
/**
* @return the productCategory3
*/
public String getProductCategory3() {
return productCategory3;
}
/**
* @param productCategory33 the productCategory3 to set
*/
public void setProductCategory3(String productCategory3) {
this.productCategory3 = productCategory3;
}
/**
* @return the purchase
*/
public String getPurchase() {
return purchase;
}
/**
* @param purchase the purchase to set
*/
public void setPurchase(String purchase) {
this.purchase = purchase;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "BlackFridayVO [userId=" + userId + ", productId=" + productId + ", gender=" + gender + ", age=" + age
+ ", occupation=" + occupation + ", cityCategory=" + cityCategory + ", stayInCurrentCityYears="
+ stayInCurrentCityYears + ", maritalStatus=" + maritalStatus + ", productCategory1=" + productCategory1
+ ", productCategory2=" + productCategory2 + ", productCategory3=" + productCategory3 + ", purchase="
+ purchase + "]";
}
}
실행 및 테스트결과
실행 후 결과를 보면 아래와 같다.
- 결과를 보면 총 5개의 작업이 분할 된 것을 확인 할 수 있으며 총 3,225,462 건이 등록 되었으며 5개의 작업에 건수
가 분할 되어서 처리된것을 볼수 있다.
작업시간은 약 4분 정도 소요 되었다.
[소스레파지토리]
☞ https://github.com/roopy1210/springbatch/blob/master/spring_batch_tutorial
'Spring Batch' 카테고리의 다른 글
TASKLET 예제 (0) | 2019.01.15 |
---|---|
ORA_HASH를 이용한 Partitioning 구현 (1) | 2018.12.26 |
Range Partitioning 예제 - 설정 (0) | 2018.12.17 |
CompositeItemWriter 예제 - 구현 (0) | 2018.12.02 |
CompositeItemWriter 예제 - 설정 (0) | 2018.12.02 |