Chunk(チャンク)処理の基本通り、
- ItemReader: Oracle Database からユーザー一覧(ID、名前、電話番号)を読み込む
- ItemProcessor: 電話番号が携帯電話番号だったときは、番号の後ろに'(携帯)'とつける加工処理
- ItemWriter: 読み込んだデータ(加工されたものもあり)を CSV ファイルに出力
という 3ステップ構成。
ただし、データが 1件もなかったときの処理や、CSV 出力に失敗したときの例外処理など、色々本物の業務バッチ処理としては足らない機能がたくさんあるので、それを勉強しながら少しずつ実装していくつもり。
まずは、そういう勉強の基盤になるソースということで、メモ代わりに貼っておく。
(プロジェクト名は 'BatchDb2Csv1')
とりあえず、
※「Oracle Database 21c Express Edition (XE) に A5 で接続」というエントリーで作成したデータ
こういうデータを Oracle Database から読み込んで、このエントリのバッチを走らせたら、
こういう CSV ファイルが吐かれます。
■application.properties
spring.application.name=BatchDB2CSV1# Oracle 接続設定spring.datasource.url=jdbc:oracle:thin:@localhost:1521/XEPDB1spring.datasource.username=testerspring.datasource.password=tester01spring.datasource.driver-class-name=oracle.jdbc.OracleDriver# アプリ起動時にSpring Batchのジョブを自動実行するspring.batch.job.enabled=true# 【重要】Spring Batch等の管理テーブルを自動作成させる設定spring.sql.init.mode=always# Spring Boot DevToolsの自動再起動を無効化する(終了前に一時停止状態になるので)spring.devtools.restart.enabled=false
YAML形式の方がお好みの方もいらっしゃるでしょうが、俺はこっちが好み。
どうも、半角スペースでインデント(字下げ)するのが(^^; Python 界隈の人は抵抗ないでしょうが(^^;;
■BatchDb2Csv1Application.java
package com.netandfield.test;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic class BatchDb2Csv1Application {public static void main(String[] args) {SpringApplication.run(BatchDb2Csv1Application.class, args);}}
■Dto/TUserDto.java
package com.netandfield.test.Dto;// DTOクラス・・・ではなく record(不変オブジェクト)でpublic record TUserDto(Long user_id, String user_name, String user_phone_number) {}■Config/BatchConfig.javapackage com.netandfield.test.Config;import javax.sql.DataSource;import org.springframework.batch.core.job.Job;import org.springframework.batch.core.job.builder.JobBuilder;import org.springframework.batch.core.repository.JobRepository;import org.springframework.batch.core.step.Step;import org.springframework.batch.core.step.builder.StepBuilder;import org.springframework.batch.infrastructure.item.ItemProcessor;import org.springframework.batch.infrastructure.item.database.JdbcCursorItemReader;import org.springframework.batch.infrastructure.item.database.builder.JdbcCursorItemReaderBuilder;import org.springframework.batch.infrastructure.item.file.FlatFileItemWriter;import org.springframework.batch.infrastructure.item.file.builder.FlatFileItemWriterBuilder;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.core.io.FileSystemResource;import org.springframework.jdbc.core.DataClassRowMapper;import org.springframework.transaction.PlatformTransactionManager;import com.netandfield.test.Dto.TUserDto;@Configurationpublic class BatchConfig {private final JobRepository jobRepository;private final PlatformTransactionManager transactionManager;private final DataSource dataSource;// コンストラクタ注入public BatchConfig(JobRepository jobRepository, PlatformTransactionManager transactionManager, DataSource dataSource){this.jobRepository = jobRepository;this.transactionManager = transactionManager;this.dataSource = dataSource;}// 1. Reader: Oracle DBからデータを読み込む@Beanpublic JdbcCursorItemReader<TUserDto> reader() {return new JdbcCursorItemReaderBuilder<TUserDto>().dataSource(dataSource).name("oracleItemReader").sql("SELECT user_id, user_name, user_phone_numberFROM t_users ORDER BY user_id ASC").rowMapper(new DataClassRowMapper<>(TUserDto.class)) // RowMapperでResultSet(検索結果オブジェクト)をDTOへマッピング.fetchSize(1000) // Oracleのパフォーマンス最適化(1,000行ずつ読込).build();}// 2. Processor: データを加工する@Beanpublic ItemProcessor<TUserDto, TUserDto> processor() {return item -> {String phone = item.user_phone_number(); // DtoがRecordの場合のゲッター。通常のクラスなら getUser_phone_number()// 電話番号が null でなく、かつ 090 または 080 で始まる場合if (phone != null && (phone.startsWith("090") || phone.startsWith("080"))) {// 文字列を追加した新しいDtoを作成して返す// (DtoがRecordの場合はイミュータブル(不変)なので、このように新しくインスタンスを作る)return new TUserDto(item.user_id(),item.user_name(),phone + "(携帯)");}// 条件に当てはまらない場合は、加工せずにそのまま次に渡すreturn item;};}// 3. Writer: CSVファイルへ出力する@Beanpublic FlatFileItemWriter<TUserDto> writer() {return new FlatFileItemWriterBuilder<TUserDto>().name("csvItemWriter").resource(new FileSystemResource("C:\\work\\test\\t_users.csv")).delimited() // 区切り文字(Delimited)を使ったフォーマットで書き出すことを指定.delimiter(",") // 区切り文字をカンマに設定(省略した場合もカンマ).names("user_id", "user_name", "user_phone_number") // 出力するフィールド名.headerCallback(writer -> writer.write("ID,名前,電話番号")) // ヘッダー行.build();}// 4. Stepの定義 (Spring Batch 6 スタイル)@Beanpublic Step exportStep() {return new StepBuilder("exportStep", jobRepository).<TUserDto, TUserDto>chunk(100) // 100件ごとにコミット/出力.transactionManager(transactionManager).reader(reader()) // 読んで.processor(processor()) // 処理して.writer(writer()) // 書き出す.build();}// 5. Jobの定義@Beanpublic Job exportJob() {return new JobBuilder("exportJob", jobRepository).start(exportStep()).build();}}
とこんな感じで。
次は、DBから 1件も取得できなかったときとか、CSVに出力するレコードが
0件とか(出力する?しない?ヘッダだけ出す?出さない?)、あと例外処理か。そういうのを追加していこう。
電気ウナギ的○○
About Backコメント(0)
電気ウナギ的○○