23.06.15
DEVOTEE를 활성화 시키면
지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.
버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.
| 컨텐츠 유형 | 제목 | 저장일 | 삭제 |
|---|
본인인증 로그인에 실패하였습니다.
회원이 아니시거나 본인인증 등록이
완료되지 않은 사용자입니다.
여전히 Spring Java 기반의 프로젝트에서 많이 사용하고 있는 ORM(?) 툴중의 하나는 MyBatis이다.
직관적인 사용법과, 쿼리를 mapper 파일에 직접 기술하고, 이를 DB Tool을 통해 수행할 수 있는 장점이 있는 도구라서 여전히 인기가 있는것 같다.
MyBatis를 Spring Batch에서 사용하는 방법을 알아보자.
MyBatisPagingItemReader Spring Mybatis에서 제공하는 ItemReader 인터페이스를 구현하는 클래스이다.
MyBatis의 Object Relation Mapper를 이용하며 다음과 같은 특징을 가지고 있다.
간편한 설정: MyBatis 쿼리 매퍼를 직접 활용하여 데이터를 읽을 수 있어 설정이 간편하다.
쿼리 최적화: MyBatis의 다양한 기능을 활용하여 최적화된 쿼리를 작성할 수 있다.
동적 쿼리 지원: 런타임 시 조건에 따라 동적으로 쿼리를 생성할 수 있다.
MyBatis 의존성: MyBatis 라이브러리에 의존해야 한다.
커스터마이징 복잡: Chunk-oriented Processing 방식과 비교했을 때 커스터마이징이 더 복잡할 수 있다.
SqlSessionFactory: MyBatis 설정 정보 및 SQL 쿼리 매퍼 정보를 담고 있는 객체이다.
QueryId: 데이터를 읽을 MyBatis 쿼리 ID이다.
PageSize: 페이징 쿼리를 위한 페이지 크기를 지정한다.
MyBatisPagingItemReader SqlSessionFactory 객체를 통해 MyBatis와 연동된다.
SqlSessionFactory는 다음과 같은 방법으로 설정할 수 있다.
@Bean 어노테이션을 사용하여 직접 생성
Spring Batch XML 설정 파일에서 설정
Java 코드에서 직접 설정
MyBatisPagingItemReader setQueryId() 메소드를 통해 데이터를 읽을 MyBatis 쿼리 ID를 설정한다.
쿼리 ID는 com.example.mapper.CustomerMapper.selectCustomers 와 같은 형식으로 지정된다.
MyBatisItemReader는 pageSize를 이용하여 offset, limit 을 이용하는 기준을 설정할 수 있다.
SkippableItemReader: 오류 발생 시 해당 Item을 건너뛸 수 있도록 한다.
ReadListener: 읽기 시작, 종료, 오류 발생 등의 이벤트를 처리할 수 있도록 한다.
SaveStateCallback: 잡의 중단 시 현재 상태를 저장하여 재시작 시 이어서 처리할 수 있도록 한다.
package com.schooldevops.springbatch.batchsample.jobs.models;
import lombok.Data;
@Data
public class Customer {
private Long id;
private String name;
private int age;
private String gender;
}Customer 객체를 지정한다.
@Bean
public MyBatisPagingItemReader<Customer> myBatisItemReader() throws Exception {
return new MyBatisPagingItemReaderBuilder<Customer>()
.sqlSessionFactory(sqlSessionFactory)
.pageSize(CHUNK_SIZE)
.queryId("com.schooldevops.springbatch.batchsample.jobs.selectCustomers")
.build();
}MyBatisPagingItemReader 를 이용하여 DB 쿼리 결과를 읽을 수 있도록 ItemReader를 반환한다.
sqlSessionFactory: 세션 팩토리를 지정한다.
pageSize: 페이징 단위를 지정한다.
parameterValues: 파라미터를 전달할 수 있다.
customer.xml 파일을 지정하고 다음과 같이 쿼리를 작성한다.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.schooldevops.springbatch.batchsample.jobs">
<resultMap id="customerResult" type="com.schooldevops.springbatch.batchsample.jobs.models.Customer">
<result property="id" column="id"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
<result property="gender" column="gender"/>
</resultMap>
<select id="selectCustomers" resultMap="customerResult">
SELECT id, name, age, gender
FROM customer
LIMIT #{_skiprows}, #{_pagesize}
</select>
</mapper>namespace: 쿼리들을 그룹화해서 모아놓은 이름 공간이다.
resultMap: 결과로 반환할 결과맵을 지정한다. 이는 db 칼럼과, java 필드 이름을 매핑한다.
select: 쿼리를 지정한다.
#{_skiprows}: 오프셋을 이야기하며, 쿼리 결과에서 얼마나 스킵할지 지정한다. pageSize를 지정했다면 자동으로 계산된다.
#{_pagesize}: 한번에 가져올 페이지를 지정한다.
package com.schooldevops.springbatch.batchsample.jobs.mybatis;
import com.schooldevops.springbatch.batchsample.jobs.models.Customer;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.batch.MyBatisPagingItemReader;
import org.mybatis.spring.batch.builder.MyBatisPagingItemReaderBuilder;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.item.file.FlatFileItemWriter;
import org.springframework.batch.item.file.builder.FlatFileItemWriterBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.FileSystemResource;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
@Slf4j
@Configuration
public class MyBatisReaderJobConfig {
/**
* CHUNK 크기를 지정한다.
*/
public static final int CHUNK_SIZE = 2;
public static final String ENCODING = "UTF-8";
public static final String MYBATIS_CHUNK_JOB = "MYBATIS_CHUNK_JOB";
@Autowired
DataSource dataSource;
@Autowired
SqlSessionFactory sqlSessionFactory;
@Bean
public MyBatisPagingItemReader<Customer> myBatisItemReader() throws Exception {
return new MyBatisPagingItemReaderBuilder<Customer>()
.sqlSessionFactory(sqlSessionFactory)
.pageSize(CHUNK_SIZE)
.queryId("com.schooldevops.springbatch.batchsample.jobs.selectCustomers")
.build();
}
@Bean
public FlatFileItemWriter<Customer> customerCursorFlatFileItemWriter() {
return new FlatFileItemWriterBuilder<Customer>()
.name("customerCursorFlatFileItemWriter")
.resource(new FileSystemResource("./output/customer_new_v4.csv"))
.encoding(ENCODING)
.delimited().delimiter("\t")
.names("Name", "Age", "Gender")
.build();
}
@Bean
public Step customerJdbcCursorStep(JobRepository jobRepository, PlatformTransactionManager transactionManager) throws Exception {
log.info("------------------ Init customerJdbcCursorStep -----------------");
return new StepBuilder("customerJdbcCursorStep", jobRepository)
.<Customer, Customer>chunk(CHUNK_SIZE, transactionManager)
.reader(myBatisItemReader())
.processor(new CustomerItemProcessor())
.writer(customerCursorFlatFileItemWriter())
.build();
}
@Bean
public Job customerJdbcCursorPagingJob(Step customerJdbcCursorStep, JobRepository jobRepository) {
log.info("------------------ Init customerJdbcCursorPagingJob -----------------");
return new JobBuilder(MYBATIS_CHUNK_JOB, jobRepository)
.incrementer(new RunIdIncrementer())
.start(customerJdbcCursorStep)
.build();
}
}여기서는 MyBatis를 이용하여, 페이징을 이용한 청크단위 처리를 수행했다.
Mybatis는 쿼리를 직접 작성하고, 쿼리 내용직접 최적화 할수 있는 장점이 있다.
pageSize를 이용하면 자동으로 offset과 pagesize를 자동으로 계산하여 페이징 처리를 수행해준다.
ItemWriter은 단순하게 파일로 작성한 예제를 확인했다.
MyBatisBatchItemWriter Spring Batch에서 제공하는 ItemWriter 인터페이스를 구현하는 클래스이다.
데이터를 MyBatis를 통해 데이터베이스에 저장하는 데 사용된다.
SqlSessionTemplate: MyBatis SqlSession 생성 및 관리를 위한 템플릿 객체이다.
SqlSessionFactory: SqlSessionTemplate 생성을 위한 팩토리 객체이다.
StatementId: 실행할 MyBatis SQL 맵퍼의 스테이tement ID이다.
ItemToParameterConverter: 객체를 ParameterMap으로 변경할수 있다.
ORM 연동: MyBatis를 통해 다양한 데이터베이스에 데이터를 저장할 수 있다.
SQL 쿼리 분리: SQL 쿼리를 Java 코드로부터 분리하여 관리 및 유지 보수가 용이하다.
유연성: 다양한 설정을 통해 원하는 방식으로 데이터를 저장할 수 있다.
설정 복잡성: MyBatis 설정 및 SQL 맵퍼 작성이 복잡할 수 있다.
데이터베이스 종속: 특정 데이터베이스에 종속적이다.
오류 가능성: 설정 오류 시 데이터 손상 가능성이 있다.
customer.xml 파일을 다음과 같이 작성한다.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.schooldevops.springbatch.batchsample.jobs">
<resultMap id="customerResult" type="com.schooldevops.springbatch.batchsample.jobs.models.Customer">
<result property="id" column="id"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
<result property="gender" column="gender"/>
</resultMap>
<insert id="insertCustomers" parameterType="com.schooldevops.springbatch.batchsample.jobs.models.Customer">
INSERT INTO customer2(name, age, gender) VALUES (#{name}, #{age}, #{gender});
</insert>
</mapper> @Bean
public MyBatisBatchItemWriter<Customer> mybatisItemWriter() {
return new MyBatisBatchItemWriterBuilder<Customer>()
.sqlSessionFactory(sqlSessionFactory)
.statementId("com.schooldevops.springbatch.batchsample.jobs.insertCustomers")
.build();
}Map으로 파라미터를 전달한다면 다음과 같이 작성할수도 있다.
@Bean
public MyBatisBatchItemWriter<Customer> mybatisItemWriter() {
return new MyBatisBatchItemWriterBuilder<Customer>()
.sqlSessionFactory(sqlSessionFactory)
.statementId("com.schooldevops.springbatch.batchsample.jobs.insertCustomers")
.itemToParameterConverter(item -> {
Map<String, Object> parameter = new HashMap<>();
parameter.put("name", item.getName());
parameter.put("age", item.getAge());
parameter.put("gender", item.getGender());
return parameter;
})
.build();
}ID,Name,Age,Female
1,unclebae,40,Male
2,superman,45,Male
3,WonderWoman,30,Female지금까지 MyBatisBatchItemWriter를 작성해 보았다.
mybatis를 이용하여 ORM을 이용하고자 한다면 MyBatisBatchItemWriter로 청크단위 업데이트를 수행할 수 있다.
쿼리를 xml로 작성하고, 쿼리를 statementId를 통해서 조회하여 해당 쿼리를 수행하여 데이터를 DB에 밀어 넣었다.
DEVOTEE를 활성화 시키면
지금 작성한 댓글에 AI가 댓글을 달아줍니다.