From ebfdc7b9019f5b7b23de02f4977b141f8122cd91 Mon Sep 17 00:00:00 2001 From: kimjihun Date: Mon, 12 Aug 2024 00:17:06 +0900 Subject: [PATCH] =?UTF-8?q?*=20JDBC=20=EB=B9=84=EA=B5=90=EC=9A=A9=20SixBat?= =?UTF-8?q?ch=20=EC=B6=94=EA=B0=80=20close=20#9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/springbatch/batch/SixthBatch.java | 162 ++++++++++++++++++ .../controller/MainController.java | 12 ++ .../entity/CustomBeforeRowMapper.java | 25 +++ 3 files changed, 199 insertions(+) create mode 100644 src/main/java/com/example/springbatch/batch/SixthBatch.java create mode 100644 src/main/java/com/example/springbatch/entity/CustomBeforeRowMapper.java diff --git a/src/main/java/com/example/springbatch/batch/SixthBatch.java b/src/main/java/com/example/springbatch/batch/SixthBatch.java new file mode 100644 index 0000000..c1547ae --- /dev/null +++ b/src/main/java/com/example/springbatch/batch/SixthBatch.java @@ -0,0 +1,162 @@ +package com.example.springbatch.batch; + +import com.example.springbatch.entity.AfterEntity; +import com.example.springbatch.entity.BeforeEntity; +import com.example.springbatch.entity.CustomBeforeRowMapper; +import com.example.springbatch.repository.AfterRepository; +import com.example.springbatch.repository.BeforeRepository; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.JobExecutionListener; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.job.builder.JobBuilder; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.step.builder.StepBuilder; +import org.springframework.batch.item.ItemProcessor; +import org.springframework.batch.item.data.RepositoryItemReader; +import org.springframework.batch.item.data.RepositoryItemWriter; +import org.springframework.batch.item.data.builder.RepositoryItemReaderBuilder; +import org.springframework.batch.item.data.builder.RepositoryItemWriterBuilder; +import org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider; +import org.springframework.batch.item.database.JdbcBatchItemWriter; +import org.springframework.batch.item.database.JdbcPagingItemReader; +import org.springframework.batch.item.database.Order; +import org.springframework.batch.item.database.builder.JdbcBatchItemWriterBuilder; +import org.springframework.batch.item.database.builder.JdbcPagingItemReaderBuilder; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.domain.Sort; +import org.springframework.transaction.PlatformTransactionManager; + +import javax.sql.DataSource; +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; +import java.util.Map; + +@Configuration +public class SixthBatch { + + private final JobRepository jobRepository; + private final PlatformTransactionManager platformTransactionManager; + + private final BeforeRepository beforeRepository; + private final AfterRepository afterRepository; + private final DataSource dataSource; + + public SixthBatch(JobRepository jobRepository, PlatformTransactionManager platformTransactionManager, BeforeRepository beforeRepository, AfterRepository afterRepository, @Qualifier("dataDBSource") DataSource dataSource) { + + this.jobRepository = jobRepository; + this.platformTransactionManager = platformTransactionManager; + this.beforeRepository = beforeRepository; + this.afterRepository = afterRepository; + this.dataSource = dataSource; + } + + @Bean + public JobExecutionListener jobExecutionListener() { + + return new JobExecutionListener() { + + private LocalDateTime startTime; + + @Override + public void beforeJob(JobExecution jobExecution) { + startTime = LocalDateTime.now(); + } + + @Override + public void afterJob(JobExecution jobExecution) { + LocalDateTime endTime = LocalDateTime.now(); + + long nanos = ChronoUnit.NANOS.between(startTime, endTime); + double seconds = nanos / 1_000_000_000.0; + + System.out.println("Job 실행 시간: " + seconds + " 초"); + } + }; + } + + @Bean + public Job sixthJob() { + + return new JobBuilder("sixthJob", jobRepository) + .start(sixthStep()) + .listener(jobExecutionListener()) + .build(); + } + + @Bean + public Step sixthStep() { + + return new StepBuilder("sixthStep", jobRepository) + . chunk(10, platformTransactionManager) + .reader(beforeSixthReader()) + .processor(middleSixthProcessor()) + .writer(afterSixthWriter()) + .build(); + } + +// @Bean +// public RepositoryItemReader beforeSixthReader() { +// +// return new RepositoryItemReaderBuilder() +// .name("beforeReader") +// .pageSize(10) +// .methodName("findAll") +// .repository(beforeRepository) +// .sorts(Map.of("id", Sort.Direction.ASC)) +// .build(); +// } + + @Bean + public JdbcPagingItemReader beforeSixthReader() { + + return new JdbcPagingItemReaderBuilder() + .name("beforeSixthReader") + .dataSource(dataSource) + .selectClause("SELECT id, username") + .fromClause("FROM BeforeEntity") + .sortKeys(Map.of("id", Order.ASCENDING)) + .rowMapper(new CustomBeforeRowMapper()) + .pageSize(10) + .build(); + } + + @Bean + public ItemProcessor middleSixthProcessor() { + + return new ItemProcessor() { + + @Override + public AfterEntity process(BeforeEntity item) throws Exception { + + AfterEntity afterEntity = new AfterEntity(); + afterEntity.setUsername(item.getUsername()); + + return afterEntity; + } + }; + } + +// @Bean +// public RepositoryItemWriter afterSixthWriter() { +// +// return new RepositoryItemWriterBuilder() +// .repository(afterRepository) +// .methodName("save") +// .build(); +// } + + @Bean + public JdbcBatchItemWriter afterSixthWriter() { + + String sql = "INSERT INTO AfterEntity (username) VALUES (:username)"; + + return new JdbcBatchItemWriterBuilder() + .dataSource(dataSource) + .sql(sql) + .itemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>()) + .build(); + } +} diff --git a/src/main/java/com/example/springbatch/controller/MainController.java b/src/main/java/com/example/springbatch/controller/MainController.java index 495b06d..45d2650 100644 --- a/src/main/java/com/example/springbatch/controller/MainController.java +++ b/src/main/java/com/example/springbatch/controller/MainController.java @@ -73,5 +73,17 @@ public class MainController { return "ok"; } + @GetMapping("/sixth") + private String sixthApi(@RequestParam("value") String value) throws Exception { + + JobParameters jobParameters = new JobParametersBuilder() + .addString("date", value) + .toJobParameters(); + + jobLauncher.run(jobRegistry.getJob("sixthJob"), jobParameters); + + return "ok"; + } + //https://docs.spring.io/spring-batch/reference/job/configuring-launcher.html } diff --git a/src/main/java/com/example/springbatch/entity/CustomBeforeRowMapper.java b/src/main/java/com/example/springbatch/entity/CustomBeforeRowMapper.java new file mode 100644 index 0000000..8b3c389 --- /dev/null +++ b/src/main/java/com/example/springbatch/entity/CustomBeforeRowMapper.java @@ -0,0 +1,25 @@ +package com.example.springbatch.entity; + +import org.springframework.jdbc.core.RowMapper; + + +import java.sql.ResultSet; +import java.sql.SQLException; + +// Sixth 배치 JdbcPagingItemReader에서 사용하는 매퍼 +public class CustomBeforeRowMapper implements RowMapper { + + public static final String ID_COLUMN = "id"; + public static final String USERNAME_COLUMN = "username"; + + @Override + public BeforeEntity mapRow(ResultSet rs, int rowNum) throws SQLException { + + BeforeEntity beforeEntity = new BeforeEntity(); + + beforeEntity.setId(rs.getLong(ID_COLUMN)); + beforeEntity.setUsername(rs.getString(USERNAME_COLUMN)); + + return beforeEntity; + } +}