2018. 12. 2. 22:29ㆍSpring Batch
CompositeItemWriter 설정
리소스파일은 하나이고 두종류의 데이터베이스에 정보를 저장한다고 가정 해 본다면 하나의 READER와 두개의 WRITER를 구성하면 될 것이다.
이와 같은 구성을 위해 CompositeItemWriter 사용에 대한 예제이다.
이 예제의 가장 큰 목적은 2 Phase Commit을 구현하는데 있다. 하나의 데이터베이스 저장 시 오류가 난다면 전체 Transaction에 대한 Rollback처리 구현에 목적이 있다.
사전준비
이제 두개의 데이터베이스를 사용해야 하므로 기존에 설정되었던 MySQL 이외에 Oracle DB에 대한 설정이 추가 되어져야 하므로 이와 관련된
설정 파일 수정이 먼저 필요하다.
그리고 멀티 트랜잭션 관리를 위해 스프링의 ChainedTransactionManager를 사용한다.
프로젝트구조
설정파일변경
위의 프로젝트 구조에 보면 /config/batch, /sqlmap/ 아래 설정 파일에 대한 변경
▩ datasource.properteis
log4jdbc 사용 하는 경우로 해서 설정 파일이 작성 되어져 있다. 만약 log4jdbc를 사용하지 않는다면 첫 라인 주석을 풀고 두번째 라인을 주석 처리한다.
#------------------------------------------------------------------------------ # mySql Database #------------------------------------------------------------------------------ #spring.datasource.mysql.DriverClassName=com.mysql.cj.jdbc.Driver spring.datasource.mysql.DriverClassName=net.sf.log4jdbc.sql.jdbcapi.DriverSpy spring.datasource.mysql.Url=jdbc:log4jdbc:mysql://localhost:3306/mysql?useUnicode=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Seoul&useSSL=false spring.datasource.mysql.UserName=xxxx spring.datasource.mysql.Password=xxxx #------------------------------------------------------------------------------ # oracle Database #------------------------------------------------------------------------------ #spring.datasource.oracle.driverClassName=oracle.jdbc.OracleDriver spring.datasource.oracle.DriverClassName=net.sf.log4jdbc.sql.jdbcapi.DriverSpy spring.datasource.oracle.Url=jdbc:log4jdbc:oracle:thin:@localhost:1521:roopy spring.datasource.oracle.UserName=xxxx spring.datasource.oracle.Password=xxxx
▩ context-batch-datasource.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" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd"> <context:annotation-config /> <bean id="egov.propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath:/config/batch/properties/datasource.properties</value> </list> </property> </bean> <bean id="mysqlDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${spring.datasource.mysql.DriverClassName}" /> <property name="url" value="${spring.datasource.mysql.Url}" /> <property name="username" value="${spring.datasource.mysql.UserName}" /> <property name="password" value="${spring.datasource.mysql.Password}" /> <property name="initialSize" value="2" /> <property name="maxActive" value="100" /> </bean> <bean id="oracleDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${spring.datasource.oracle.DriverClassName}" /> <property name="url" value="${spring.datasource.oracle.Url}" /> <property name="username" value="${spring.datasource.oracle.UserName}" /> <property name="password" value="${spring.datasource.oracle.Password}" /> <property name="initialSize" value="2" /> <property name="maxActive" value="100" /> </bean> </beans>
- MySQL DataSource 작성
- Oracle DataSource 작성
▩ context-batch-job-launcher.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" xmlns:p="http://www.springframework.org/schema/p" 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"> <bean id="eGovBatchRunner" class="egovframework.rte.bat.core.launch.support.EgovBatchRunner"> <constructor-arg ref="jobOperator" /> <constructor-arg ref="jobExplorer" /> <constructor-arg ref="jobRepository" /> </bean> <bean id="jobOperator" class="org.springframework.batch.core.launch.support.SimpleJobOperator" p:jobLauncher-ref="jobLauncher" p:jobExplorer-ref="jobExplorer" p:jobRepository-ref="jobRepository" p:jobRegistry-ref="jobRegistry" /> <bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher"> <property name="jobRepository" ref="jobRepository" /> </bean> <bean id="jobRepository" class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean" p:dataSource-ref="mysqlDataSource" p:transactionManager-ref="transactionManager" p:isolationLevelForCreate="ISOLATION_DEFAULT" /> <bean id="jobExplorer" class="org.springframework.batch.core.explore.support.JobExplorerFactoryBean" p:dataSource-ref="mysqlDataSource" /> <bean class="org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor"> <property name="jobRegistry" ref="jobRegistry" /> </bean> <bean id="jobRegistry" class="org.springframework.batch.core.configuration.support.MapJobRegistry" /> <!-- MySQL JdbcTemplate --> <bean id="mysqlJdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="mysqlDataSource" /> </bean> <!-- Oracle JdbcTemplate --> <bean id="oracleJdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="oracleDataSource" /> </bean> </beans>
- 스프링배치 메타 테이블은 MySQL에 존재하므로 MySQL데이터소스로 변경
- JdbcTemplate 또한 MySQL과 Oracle두가지로 설정한다.
JdbcTemplate 은 Tasklet 사용 시 사용한다.
▩ context-batch-mapjob-launcher.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" xmlns:p="http://www.springframework.org/schema/p" 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"> <bean id="eGovBatchRunner" class="egovframework.rte.bat.core.launch.support.EgovBatchRunner"> <constructor-arg ref="jobOperator" /> <constructor-arg ref="jobExplorer" /> <constructor-arg ref="jobRepository" /> </bean> <bean id="jobOperator" class="org.springframework.batch.core.launch.support.SimpleJobOperator" p:jobLauncher-ref="jobLauncher" p:jobExplorer-ref="jobExplorer" p:jobRepository-ref="jobRepository" p:jobRegistry-ref="jobRegistry" /> <bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher"> <property name="jobRepository" ref="jobRepository" /> </bean> <!-- JobRepositoryFactoryBean 대신 MapJobRepositoryFactoryBean 적용 --> <bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean" p:transactionManager-ref="transactionManager" /> <bean id="jobExplorer" class="org.springframework.batch.core.explore.support.JobExplorerFactoryBean" p:dataSource-ref="mysqlDataSource" /> <bean class="org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor"> <property name="jobRegistry" ref="jobRegistry" /> </bean> <bean id="jobRegistry" class="org.springframework.batch.core.configuration.support.MapJobRegistry" /> </beans>
▩ context-batch-transaction.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" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/jdbct http://www.springframework.org/schema/jdbc/spring-jdbc.xsd"> <context:annotation-config /> <!-- MySQL TransactionManager 설정 --> <bean id="mysqlTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" lazy-init="true"> <property name="dataSource" ref="mysqlDataSource" /> </bean> <!-- Oracle TransactionManager 설정 --> <bean id="oracleTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" lazy-init="true"> <property name="dataSource" ref="oracleDataSource" /> </bean> <!-- Chained TransactionManager 설정 --> <bean id="transactionManager" class="org.springframework.data.transaction.ChainedTransactionManager"> <constructor-arg> <list> <ref bean="mysqlTransactionManager"/> <ref bean="oracleTransactionManager"/> </list> </constructor-arg> </bean> </beans>
- 데이터베이스별로 각각 TransactionManager 설정 후 ChainedTransactionManager를 통하여 하나의 Transaction으로 처리 하도록 한다.
- 만약 한쪽의 오류가 발생한다면 두객의 데이터베이스 Rollback 처리 될 것이다.(2 Phase Commit)
▩ context-mapper.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" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch-2.1.xsd"> <!-- MySql myBatis 설정 --> <bean id="mysqlSqlSession" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="mysqlDataSource" /> <property name="configLocation" value="classpath:/config/sqlmap/sql-mapper-config.xml" /> <property name="mapperLocations" value="classpath:/config/sqlmap/mysql/**/*SQL.xml" /> </bean> <bean id="mysqlSqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg index="0" ref="mysqlSqlSession" /> <constructor-arg index="1" value="SIMPLE" /> </bean> <bean id="batchMysqlSqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg index="0" ref="mysqlSqlSession" /> <constructor-arg index="1" value="BATCH" /> </bean> <!-- Oracle myBatis 설정 --> <bean id="oracleSqlSession" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="oracleDataSource" /> <property name="configLocation" value="classpath:/config/sqlmap/sql-mapper-config.xml" /> <property name="mapperLocations" value="classpath:/config/sqlmap/oracle/**/*SQL.xml" /> </bean> <bean id="oracleSqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg index="0" ref="oracleSqlSession" /> <constructor-arg index="1" value="SIMPLE" /> </bean> <bean id="batchOracleSqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg index="0" ref="oracleSqlSession" /> <constructor-arg index="1" value="BATCH" /> </bean> </beans>
- MySQL, Oracle 각각 myBatis 설정을 해준다.
- SQL 파일 위치는 나누어서 관리한다.
▩ 오라클 FIFA_RANKING 테이블 생성
CREATE TABLE SYSTEM.FIFA_RANKING ( RNK NUMBER NOT NULL, RNK_DATE VARCHAR2(8 BYTE) NOT NULL, COUNTRY_FULL VARCHAR2(50 BYTE) NULL, COUNTRY_ABRV VARCHAR2(10 BYTE) NULL, TOTAL_POINTS NUMBER NULL, PREVIOUS_POINTS NUMBER NULL, RANK_CHANGE NUMBER NULL, CUR_YEAR_AVG NUMBER NULL, CUR_YEAR_AVG_WEIGHTED NUMBER NULL, LAST_YEAR_AVG NUMBER NULL, LAST_YEAR_AVG_WEIGHTED NUMBER NULL, TWO_YEAR_AGO_AVG NUMBER NULL, TWO_YEAR_AGO_WEIGHTED NUMBER NULL, THREE_YEAR_AGO_AVG NUMBER NULL, THREE_YEAR_AGO_WEIGHTED NUMBER NULL, CONFEDERATION VARCHAR2(10 BYTE) NULL ); ALTER TABLE SYSTEM.FIFA_RANKING ADD ( CONSTRAINT PK_FIFA_RANKING PRIMARY KEY ( RNK, RNK_DATE ) USING INDEX TABLESPACE SYSTEM PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64 K NEXT 1 M MINEXTENTS 1 MAXEXTENTS UNLIMITED FREELISTS 1 FREELIST GROUPS 1 ) );
[소스레파지토리]
☞ https://github.com/roopy1210/springbatch/blob/master/spring_batch_tutorial
'Spring Batch' 카테고리의 다른 글
Range Partitioning 예제 - 설정 (0) | 2018.12.17 |
---|---|
CompositeItemWriter 예제 - 구현 (0) | 2018.12.02 |
DB To File 예제 (0) | 2018.11.14 |
MULTI FILE TO DB - 다중파일 예제 (0) | 2018.11.01 |
FILE TO DB - Fixed Length 예제 (0) | 2018.10.22 |