전자정부 프레임 배치 사용 DB 마이그레이션
전자정부 프레임에서 제공하는 DB to DB 배치를 이용하여 간단한 마이그레이션 작업이 가능할 것 같아서 시도해봄 모든 소스는 아래 gitHub에 있음
프로젝트 생성
- eGovFrame - Start - New Batch Template Project
DB to DB 작업 샘플이 필요하므로 DB 선택
바로 결과를 확인해야 하니 CommandLine 선택
프로젝트 정보를 적당히 입력해줍시다.
Maven 기반으로 아래와 같이 프로젝트가 생성됩니다.
job 파일 설정
DB to DB 작업을 위해서 샘플 파일 중 ibatisToIbatisJob.xml 파일을 복사해서 migReplcJob.xml 라고 새로운 파일을 생성했습니다. 이름은 각자 취향대로 설정하세요
job 설정
아래 예제처럼 job - step - tasklet - chunk 순서로 기술하고 step은 여러 개 작성 가능 자세한 내용은 검색…. 대충 보면 migReplcItemReader로 DB에서 읽고 migReplcProcessor로 데이터 가공 migReplcItemWriter로 DB에 쓰는 작업을 할 거라고 예측 가능
<job id="migReplcJob" parent="eGovBaseJob" xmlns="http://www.springframework.org/schema/batch">
<step id="migReplcStep" parent="eGovBaseStep">
<tasklet>
<chunk reader="migReplcItemReader" processor="migReplcProcessor"
writer="migReplcItemWriter" commit-interval="100" />
</tasklet>
</step>
</job>
reader 설정
원본 데이터를 읽어올 select 문장의 queryId 지정, 나머지는 기본 설정
<bean id="migReplcItemReader" class="org.springframework.batch.item.database.IbatisPagingItemReader">
<property name="queryId" value="selectShopInfoList" />
<property name="sqlMapClient" ref="sqlMapClient" />
<property name="dataSource" ref="dataSource" />
</bean>
writer 설정
데이터를 저장할 insert 문장의 queryId 지정, 나머지는 기본 설정
<bean id="migReplcItemWriter" class="org.springframework.batch.item.database.IbatisBatchItemWriter">
<property name="statementId" value="insertReplc" />
<property name="sqlMapClient" ref="sqlMapClient" />
<property name="dataSource" ref="dataSource" />
</bean>
processor 설정
데이터 가공이 필요할 때 사용할 bean
<bean id="migReplcProcessor" class="egovframework.example.bat.domain.replc.ReplcProcessor" />
Bean 생성
Bean을 생성할 Package 생성
VO 객체와 processor Bean 생성
Replc VO
insert 할 대상 테이블 테이블에 맞게 필드를 생성하고 생성자, toString, getter/setter 메서드 생성
package egovframework.example.bat.domain.replc;
import javax.persistence.Entity;
import javax.persistence.Table;
@Entity
@Table(name = "OB_REPLC")
public class Replc {
private String replcCode = "";
private String replcTy = "";
private String replcNm = "";
private String replcGdcc = "";
private String replcExcpGdcc = "";
private String smsDsptchNo = "";
private String replcEmail = "";
private String useAt = "";
private String scdCallUseAt = "";
private String hdqrtrsCode = "";
private String remark = "";
private String frstRegistPnttm = "";
private String frstRegisterId = "";
private String lastUpdtPnttm = "";
private String lastUpdusrId = "";
public Replc() {
}
이하 줄임...
ShopInfo VO
select 할 테이블 위 Replc VO처럼 테이블에 맞게 필드를 생성하고 생성자, toString, getter/setter 메서드 생성
Replc processor
ItemProcessor 구현하고 process 메서드를 Override함 process 메서드에서 데이터를 가공하고 return 함
package egovframework.example.bat.domain.replc;
import org.springframework.batch.item.ItemProcessor;
public class ReplcProcessor implements ItemProcessor<ShopInfo, Replc> {
public ReplcProcessor() {
}
@Override
public Replc process(ShopInfo item) throws Exception {
Replc replc = new Replc();
return replc;
}
}
쿼리 작업
sql-map-config.xml 작성
쿼리를 작성할 파일 정보 추가
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN"
"http://www.ibatis.com/dtd/sql-map-config-2.dtd">
<sqlMapConfig>
<!-- <sqlMap resource="egovframework/sqlmap/example/bat/Egov_Example_SQL.xml"/> -->
<!-- <sqlMap resource="egovframework/sqlmap/example/bat/Egov_Example_SQL_tibero.xml"/> -->
<!-- <sqlMap resource="egovframework/sqlmap/example/bat/Egov_Example_SQL_altibase.xml"/> -->
<!-- <sqlMap resource="egovframework/sqlmap/example/bat/Egov_Example_SQL_mysql.xml"/> -->
<!-- <sqlMap resource="egovframework/sqlmap/example/bat/Egov_Example_SQL_oracle.xml"/> -->
<!-- <sqlMap resource="egovframework/sqlmap/example/bat/Egov_Example_SQL_cubrid.xml"/> -->
<sqlMap resource="egovframework/sqlmap/example/bat/Egov_Replc_SQL.xml"/>
</sqlMapConfig>
Egov_Replc_SQL.xml 작성
쿼리 작성하기 전 전체 구조 shopInfo는 source 테이블 VO, replc는 target 테이블 VO
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap namespace="Replc">
<typeAlias alias="replc" type="egovframework.example.bat.domain.replc.Replc" />
<typeAlias alias="shopInfo" type="egovframework.example.bat.domain.replc.ShopInfo" />
<select id="selectShopInfoList" resultClass="shopInfo">
<![CDATA[
]]>
</select>
<insert id="insertReplc" parameterClass="replc">
<![CDATA[
]]>
</select>
</sqlMap>
selectShopInfoList 작성
SHOP_INFO 테이블 select 할때 pageing 쿼리를 사용해야함 _page, _pagesize, _skiprows 는 org.springframework.batch.item.database.IbatisPagingItemReader 에 정의되어 있음
<select id="selectShopInfoList" resultClass="shopInfo">
<![CDATA[
SELECT
*
FROM
(
SELECT
rownum AS rn
, TB.*
FROM
(
SELECT
shop_code AS shopCode
, shop_type AS shopType
, shop_name AS shopName
, usr_id AS usrId
, shop_cal_sct AS shopCalSct
, shop_sms_sct AS shopSmsSct
, shop_sms_mk AS shopSmsMk
, shop_sms_abs_sct AS shopSmsAbsSct
, shop_sms_abs_mk AS shopSmsAbsMk
, shop_sms_sedno AS shopSmsSedno
, shop_exc AS shopExc
, shop_email AS shopEmail
, shop_del_mk AS shopDelMk
, shop_remark AS shopRemark
, reg_id AS regId
, TO_CHAR(reg_dt, 'YYYYMMDDHH24MISS') AS regDt
, chg_id AS chgId
, TO_CHAR(chg_dt, 'YYYYMMDDHH24MISS') AS chgDt
, shop_ot_seq AS shopOtSeq
, regn_fg AS regnFg
, shop_sms_res_sct AS shopSmsResSct
, shop_sms_res_mk AS shopSmsResMk
, shop_sms_resb_sct AS shopSmsResbSct
, shop_sms_resb_mk AS shopSmsResbMk
, cal2_usr_mk AS cal2UsrMk
FROM
shop_info
WHERE
1 = 1
ORDER BY
shop_code
) TB
WHERE
rownum <= (#_page# + 1) * #_pagesize#
)
WHERE
rn >= #_skiprows# + 1
]]>
</select>
shopInfo 를 replc 로 변환
process 메서드에서 SHOP_INFO 에서 select 한 필드를 OB_REPLC 테이블에 세팅해서 return 한다. return 된 replc VO 는 insertReplc 쿼리에서 사용된다.
package egovframework.example.bat.domain.replc;
import org.springframework.batch.item.ItemProcessor;
public class ReplcProcessor implements ItemProcessor<ShopInfo, Replc> {
public ReplcProcessor() {
}
@Override
public Replc process(ShopInfo item) throws Exception {
Replc replc = new Replc();
replc.setReplcCode(item.getShopCode());
replc.setReplcTy(item.getShopType());
replc.setReplcNm(item.getShopName());
replc.setReplcGdcc(item.getShopCalSct());
replc.setSmsDsptchNo(item.getShopSmsSedno());
replc.setReplcExcpGdcc(item.getShopExc());
replc.setReplcEmail(item.getShopEmail());
replc.setUseAt(item.getShopDelMk());
replc.setRemark(item.getShopRemark());
replc.setFrstRegisterId(item.getRegId());
replc.setFrstRegistPnttm(item.getRegDt());
replc.setLastUpdusrId(item.getChgId());
replc.setLastUpdtPnttm(item.getChgDt());
replc.setHdqrtrsCode(item.getRegnFg());
replc.setScdCallUseAt(item.getCal2UsrMk());
return replc;
}
}
insertReplc 작성
<insert id="insertReplc" parameterClass="replc">
<![CDATA[
INSERT INTO
ob_replc (
replc_code
, replc_ty
, replc_nm
, replc_gdcc
, replc_excp_gdcc
, sms_dsptch_no
, replc_email
, use_at
, scd_call_use_at
, hdqrtrs_code
, remark
, frst_regist_pnttm
, frst_register_id
, last_updt_pnttm
, last_updusr_id
)
VALUES (
#replcCode#
, #replcTy#
, #replcNm#
, #replcGdcc#
, #replcExcpGdcc#
, #smsDsptchNo#
, #replcEmail#
, #useAt#
, #scdCallUseAt#
, #hdqrtrsCode#
, #remark#
, TO_DATE(#frstRegistPnttm#, 'YYYYMMDDHH24MISS')
, #frstRegisterId#
, TO_DATE(#lastUpdtPnttm#, 'YYYYMMDDHH24MISS')
, #lastUpdusrId#
)
]]>
</insert>
dataSource 설정
읽어올 DB와 저장할 DB가 다르기 때문에 각각 dataSource를 설정해야 함 본 예제에서는 Oracle 데이터베이스를 사용함
context-batch-datasource.xml 설정
공통 propertise 파일 import
<bean id="egov.propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:/egovframework/batch/properties/globals.properties</value>
</list>
</property>
</bean>
dataSource-oracle 데이터를 저장할 target DB 정보 dataSource-oracle-0 데이터를 읽어올 source DB 정보 나머지 설정은 그대로 유지
<!-- DataSource -->
<alias name="dataSource-${Globals.DbType}" alias="egov.dataSource"/>
<alias name="dataSource-${Globals.DbType}" alias="dataSource"/> <!-- target -->
<alias name="dataSource-${Globals.DbType}-0" alias="dataSource0"/> <!-- source -->
<!-- Oracle -->
<!-- target -->
<bean id="dataSource-oracle" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${Globals.DriverClassName}"/>
<property name="url" value="${Globals.Url}"/>
<property name="username" value="${Globals.UserName}"/>
<property name="password" value="${Globals.Password}"/>
</bean>
<!-- source -->
<bean id="dataSource-oracle-0" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${Globals.DriverClassName}"/>
<property name="url" value="${Globals.Url0}" />
<property name="username" value="${Globals.UserName0}"/>
<property name="password" value="${Globals.Password0}"/>
</bean>
globals.properties 설정
데이터를 읽어올 DB와 저장할 DB 정보를 설정
# DB서버 타입(hsql, mysql, oracle, altibase, tibero, cubrid) - datasource 및 sqlMap 파일 지정에 사용됨
Globals.DbType = oracle
#oracle
Globals.DriverClassName=oracle.jdbc.driver.OracleDriver
Globals.Url=jdbc:oracle:thin:@ec4.dev:1521:xe
Globals.UserName=로그인id
Globals.Password=로그인pass
Globals.Url0=jdbc:oracle:thin:@ec4.dev:1523:xe
Globals.UserName0=로그인id
Globals.Password0=로그인pass
오라클 드라이버 ojdbc6.jar
pom.xml에 설정함 저는 maven 로컬 저장소를 운영하기 때문에 아래처럼 설정하면 되지만 이글을 보고 하시는 분은 다른 방법으로 해결하시기 바랍니다. classpath에 ojdbc6.jar 파일이 걸려있으면 됩니다.
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.4.0</version>
</dependency>
job 수정
migReplcJob의 migReplcItemReader는 위에서 설정한 dataSource0 을 사용하게 수정 읽어오는 DB와 저장하는 DB 구분
<bean id="migReplcItemReader" class="org.springframework.batch.item.database.IbatisPagingItemReader">
<property name="queryId" value="selectShopInfoList" />
<property name="sqlMapClient" ref="sqlMapClient" />
<property name="dataSource" ref="dataSource0" />
</bean>
실행하기
EgovCommandLineJobRunner.java 우클릭 - Run As - Run Configurations 파라메터로 공통 설정파일 위치와 실행할 job 이름 입력