前提・実現したいこと
SpringBatchとMyBatisを使ってCSVをデータベースに登録するバッチを作成しています。
バッチはチャンクモデルで作成していて、以下のような構成になっています。
- ItemReader・・・アクティブテーブルを読む
- ItemProcessor・・・アクティブデータに登録されているパスのCSVを読む
- ItemWriter・・・CSVファイルの中身を登録する
1のアクティブテーブルは、他システムが登録しているもので、キー情報とCSVのファイルパスが登録されています。
ItemProcessorでそのファイルを読み込み、フォーマットを統一してListに詰めます。
ItemWriterでListを受取ってDBに登録します。
最初に調べた時に、StepBuilderFactoryにchunk(1000)
など設定しておくと、1000件ずつコミットしてくれると理解しました。
が、実際に動かしてみて初めて、CSVファイルの中身の件数じゃなくて、Readerで取得されるデータの件数で制御されることに気づきました…。
どのようにしたら分割でコミットができるのでしょうか?
発生している問題・エラーメッセージ
org.springframework.dao.TransientDataAccessResourceException: batch.XXXMapper.insertBulk (batch index #1) failed. Cause: java.sql.tion: Packet for query is too large (5,636,232 > 4,194,304). You can change this value on the server by setting the 'max_allowed_packet' variable.
max_allowed_packetを変えたらいいよと言われてるのは分かるのですが、このファイルが最大という訳でもないので分割でコミットしたいと思ってます。
該当のソースコード
■Step
java
1 @Bean 2 public Step insertCsvStep( 3 ItemReader<Activity> reader, 4 ItemProcessor<Activity, List<XXXData>> processor, 5 ItemWriter<List<XXXData>> writer) { 6 return stepBuilderFactory.get("insertCsvStep") 7 .<Activity, List<XXXData>> chunk(1000) 8 .reader(reader) 9 .processor(processor) 10 .writer(writer) 11 .build(); 12 }
■ItemReader
※単純にデータを取ってくるだけなので省略(多くて10件ぐらい)
■ItemProcessor
※ファイルによって項目数が違うのでsplitで分割しながら読んでます
java
1 @Override 2 public List<XXXData> process(Activity activity) throws Exception { 3 BufferedReader br = null; 4 // ItemWriterに渡すリスト 5 List<XXXData> result = new ArrayList<XXXData>(); 6 try { 7 File f = new File(activity.getPath()); 8 br = new BufferedReader(new FileReader(f)); 9 10 String sLine; 11 while ((sLine = br.readLine()) != null) { 12 csv = sLine.split(",", 0); 13 14 XXXData data = new XXXData(); 15 : 16 (諸々の加工処理) 17 : 18 result.add(data); 19 } 20 } catch (Exception e) { 21 // 省略 22 } finally { 23 if(br != null) br.close(); 24 } 25 return result; 26 }
■ItemWriter
java
1 @Bean 2 public MyBatisBatchItemWriter<List<XXXData>> insertXXXData() { 3 return new MyBatisBatchItemWriterBuilder<List<XXXData>>() 4 .sqlSessionFactory(sqlSessionFactory) 5 .statementId("batch.infra.mapper.XXXDataMapper.insertBulk") 6 .build(); 7 }
■Mapper(xml)
xml
1 <insert id="insertBulk" parameterType="java.util.List"> 2 INSERT INTO xxx_data ( 3 system_id, 4 : 5 ) 6 VALUES 7 <foreach item="record" collection="list" separator=","> 8 ( 9 #{record.system_id,jdbcType=VARCHAR}, 10 : 11 ) 12 </foreach> 13 </insert>
試したこと
application.ymlで下記のように設定を追加してみましたが、同じでした。
yml
1mybatis: 2 executor-type: BATCH 3 configuration: 4 default-executor-type: BATCH
補足情報(FW/ツールのバージョンなど)
SpringBoot2.3.1(プロジェクト作成時にSpringBatchを選択)
Java 13
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。