J'ai essayé le traitement par lots à l'aide de tasklet. J'utilise également les curseurs MyBatis pour gérer le chargement en masse des tables.
Créez un projet à l'aide de Spring Initializr. Dans Dépendances, sélectionnez Batch, Lombok, MyBatis et le pilote DBC pour votre base de données (mon article utilise MySQL).
application.properties
#Niveau de journal
logging.level.com.sample.demo=debug
#Informations de connexion à la base de données
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/demo?characterEncoding=UTF-8&serverTimezone=JST&sslMode=DISABLED
spring.datasource.username=hoge
spring.datasource.password=hoge
#Extraire la taille
#mybatis.configuration-properties.default-fetch-size=10000
mybatis.configuration-properties.fetch-size=10000
#Taille d'écriture du fichier
demo.write-size=1000
Lisez le DB et sortez le fichier.
DemoTasklet.java
package com.sample.demo;
import java.util.ArrayList;
import java.util.List;
import org.apache.ibatis.cursor.Cursor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.item.ItemStreamWriter;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component()
public class DemoTasklet implements Tasklet {
private Logger logger = LoggerFactory.getLogger(DemoTasklet.class);
@Autowired
private DemoRepository demoRepository;
@Autowired
private ItemStreamWriter<DemoDTO> writer;
@Autowired
private DemoContext demoContext;
public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
logger.debug("DemoTasklet exécute démarrer");
writer.open(chunkContext.getStepContext().getStepExecution().getExecutionContext());
try(Cursor<DemoDTO> result = demoRepository.select()) {
List<DemoDTO> data = new ArrayList<>();
for(DemoDTO dto: result) {
data.add(dto);
if (data.size() >= demoContext.getWriteSize()) {
writer.write(data);
data.clear();
}
}
if (data.size() > 0) writer.write(data);
}
writer.close();
logger.debug("Exécution de DemoTasklet terminée");
return RepeatStatus.FINISHED;
}
}
Enregistrez le Tasklet et définissez le fichier CSV.
BatchConfig.java
package com.sample.demo;
import java.io.IOException;
import java.io.Writer;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.item.file.FlatFileHeaderCallback;
import org.springframework.batch.item.file.FlatFileItemWriter;
import org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor;
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.core.io.Resource;
@Configuration
@EnableBatchProcessing
public class BatchConfig {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Autowired
private DemoTasklet demoTasklet;
private Resource outputResource = new FileSystemResource("output/data.csv");
@Bean
public DemoContext createDemoContext() {
return new DemoContext();
}
@Bean
public FlatFileItemWriter<DemoDTO> writer()
{
FlatFileItemWriter<DemoDTO> writer = new FlatFileItemWriter<>();
writer.setResource(outputResource);
writer.setEncoding("UTF-8");
writer.setLineSeparator("\r\n");
writer.setAppendAllowed(false);
writer.setHeaderCallback(new FlatFileHeaderCallback() {
public void writeHeader(Writer arg0) throws IOException {
arg0.append("\"ID\",\"Nom\",\"adresse mail\"");
}
});
writer.setLineAggregator(new CsvLineAggregator<DemoDTO>() {
{
setFieldExtractor(new BeanWrapperFieldExtractor<DemoDTO>() {
{
setNames(new String[] { "id", "name", "mailAddress" });
}
});
}
});
return writer;
}
@Bean
public Step step1() {
return stepBuilderFactory.get("step1").tasklet(demoTasklet).build();
}
@Bean
public Job job(Step step1) {
return jobBuilderFactory.get("job").incrementer(new RunIdIncrementer()).start(step1).build();
}
}
La valeur-clé définie dans [demo.] Dans application.properties est définie.
DemoContext.java
package com.sample.demo;
import org.springframework.boot.context.properties.ConfigurationProperties;
import lombok.Data;
@ConfigurationProperties(prefix="demo")
@Data
public class DemoContext {
private int writeSize;
}
Si vous utilisez la classe préparée par spring, vous ne pouvez pas définir le caractère de la boîte, donc si vous voulez définir le caractère de la boîte, vous devez créer le vôtre.
CsvLineAggregator.java
package com.sample.demo;
import java.util.Arrays;
import org.springframework.batch.item.file.transform.ExtractorLineAggregator;
import org.springframework.util.StringUtils;
public class CsvLineAggregator<T> extends ExtractorLineAggregator<T> {
private String enclose = "\"";
private String delimiter = ",";
public void setEnclose(String enclose) {
this.enclose = enclose;
}
public void setDelimiter(String delimiter) {
this.delimiter = delimiter;
}
@Override
protected String doAggregate(Object[] fields) {
return StringUtils.collectionToDelimitedString(Arrays.asList(fields), this.delimiter, this.enclose, this.enclose);
}
}
DTO
DemoDTO.java
package com.sample.demo;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Data
public class DemoDTO {
private String id;
private String name;
private String mailAddress;
}
Interface pour SQL
DemoRepository.java
package com.sample.demo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.cursor.Cursor;
@Mapper
public interface DemoRepository {
Cursor<DemoDTO> select();
}
SQL
DemoRepository.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.sample.demo.DemoRepository">
<select id="select" resultType="com.sample.demo.DemoDTO" fetchSize="${fetch-size}">
SELECT
id,
name,
mail_address as mailAddress
FROM
users
</select>
</mapper>
Recommended Posts