spring batch 批处理框架的使用

微信公众号地址: https://mp.weixin.qq.com/s?__biz=MzIyOTk1NjUyOQ==&mid=2247483652&idx=1&sn=3e75e674eaa9bdd81c5643152a6a2299&chksm=e8bb8fdadfcc06cc2dc557fd386daad713fa38a84a3e448c3c412d7e793106cdc46835b05904#rd

 

前言: 参考来自 spring 官方文档,地址链接: https://spring.io/guides/gs/batch-processing/

spring batch 。spring batch 是一个大数据量的批处理框架,使用场景,比如每天都要定时的从文件中读取数据,然后插入到数据库中,而spring batch 可以承受数百万上千万的数据量,当然,如果在数据量不大情况下,可以直接读取数据文件,然后读取文件内容到内存中,然后for循环插入到数据库中,这在数据量不大情况下,还是挺好用的。

1.1 创建一个 dto,对应文件中的字段类型,

@Getter@Setter@ToString
public class PreUser implements Serializable {
    private String name;

    private String phone;

    private String picture;

    private Integer sex;

}

1.2 创建一个 domain,跟数据库中的表对应

@Getter@Setter@ToString(callSuper = true)
public class User extends BaseDomain{
    private String name;

    private String phone;

    private String picture;

    private Integer sex;

    public String getSexName(){
        String sexName = null;
        if(sex != null){
            switch (sex){
                case 1 : sexName = "男";break;
                case 0 : sexName = "女";break;
                default: sexName = "unkonw";
            }
        }
        return sexName;
    }
}

BaseDomain 是一个基础类,包含数据库表中的必备字段,包含 id,创建时间,创建人,修改时间,修改人等五个信息,

@Getter@Setter@ToString
public class BaseDomain implements Serializable {
    private Integer id;
    private String createBy;
    private Date credateAt;
    private String updateBy;
    private Date updateAt;
}

2.1 创建一个 processor,process 类继承自org.springframework.batch.item.ItemProcessor 接口,输入为PreUser(即从文件中读取的信息),输出为User类(即对应数据库中的类),

public class UserItemProcessor implements ItemProcessor {
    @Override
    public User process(PreUser item) throws Exception {
        User user = new User();
        user.setUpdateBy("system");
        user.setCreateBy("system");
        user.setUpdateAt(new Date());

        user.setSex(item.getSex());
        user.setPicture(item.getPicture());
        user.setPhone(item.getName());
        user.setName(item.getName());
        return user;
    }
}

2.2 自定义一个writer,spring batch 也给我们提供了很多的writer,不过这里没有使用,以为在实际中我们会在项目里面集成orm框架,这里使用的是mybatis,自定义一个mapper类来将数据插入数据库。

@Slf4j
@Component
public class UserItemWriter implements ItemWriter {

    @Resource
    private UserMapper userMapper;

    @Override
    public void write(List items) throws Exception {
        for (User item : items) {
            Integer insert = userMapper.insert(item);
            log.info("insert result [{}],{{}},[{}]",insert,item.getName(),item.getPhone());
        }
    }
}

2.3 自定义一个 listener,用于监听在job执行完后,自定义的操作。

@Component
@Slf4j
public class JobCompletionNotificationListener extends JobExecutionListenerSupport {
    @Autowired
private UserService userService;

    @Override
    public void afterJob(JobExecution jobExecution) {
        if(jobExecution.getStatus() == BatchStatus.COMPLETED){
            List users = userService.listAll();
            for (User user : users) {
                log.info("insert data [{}],[{}],[{}],[{}]",user.getName(),user.getPhone(),user.getPicture(),user.getSexName());
            }
        }
    }
}

 

3 装载配置文件 

3.1 输入使用 FlatFileItemReader 来读取csv文件

3.2 组装一个上一步自定义的  UserItemProcessor

3.3 组装一个 Step , Step 里面设置之前组装好的reader,process,writer

3.4 组装一个 Job ,Job  里面设置好 Setp ,Listener 等信息。

@Configuration
@EnableBatchProcessing
public class BatchConfiguration {
    @Autowired
    JobBuilderFactory jobBuilderFactory;

    @Autowired
    StepBuilderFactory stepBuilderFactory;

    @Autowired
    private UserItemWriter userItemWriter;

    @Bean
    public FlatFileItemReader reader(){
        return new FlatFileItemReaderBuilder()
                .name("personItemReader")
                .resource(new ClassPathResource("sample-data.csv"))
                .delimited()
                .names(new String[]{"name", "phone", "picture", "sex"})
                .fieldSetMapper(new BeanWrapperFieldSetMapper(){ {
                    setTargetType(PreUser.class);
                }})
                .build();

    }



    @Bean
    public UserItemProcessor processor(){
        return new UserItemProcessor();
    }




    @Bean
    public Job importUserJob(JobCompletionNotificationListener listener, Step step1) {
        return jobBuilderFactory.get("importUserJob")
                .incrementer(new RunIdIncrementer())
                .listener(listener)
                .flow(step1)
                .end()
                .build();
    }

    @Bean
    public Step step1() {
        return stepBuilderFactory.get("step1")
                . chunk(10)
                .reader(reader())
                .processor(processor())
                .writer(userItemWriter)
                .build();
    }


    /**
     * 作业仓库
     *
     * @param dataSource
     * @param transactionManager
     * @return
     * @throws Exception
     */
    @Bean
    public JobRepository jobRepository(DataSource dataSource, PlatformTransactionManager transactionManager) throws Exception{

        JobRepositoryFactoryBean jobRepositoryFactoryBean = new JobRepositoryFactoryBean();
        jobRepositoryFactoryBean.setDataSource(dataSource);
        jobRepositoryFactoryBean.setTransactionManager(transactionManager);
        jobRepositoryFactoryBean.setDatabaseType(DatabaseType.MYSQL.name());

        return jobRepositoryFactoryBean.getObject();
    }

    /**
     * 作业调度器
     *
     * @param dataSource
     * @param transactionManager
     * @return
     * @throws Exception
     */
    @Bean
    public SimpleJobLauncher jobLauncher(DataSource dataSource, PlatformTransactionManager transactionManager) throws Exception{

        SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
        jobLauncher.setJobRepository(this.jobRepository(dataSource, transactionManager));

        return jobLauncher;
    }

    @Bean
    public MyJobListener myJobListener(){
        return new MyJobListener();
    }
}

 

4  配置 joblancher 等信息。到这里我们已经把 job 给配置好了 ,但是还不能执行,在上面的配置文件中,我们还初始化了 JobRepository(作业仓库),

SimpleJobLauncher (作业调度器),MyJobListener (Job监听器)。在这个test类中 作业调度器来执行job。最终的效果是文件被读取到数据库中。

@Slf4j
public class TestJob extends HellenBatchApplicationTests {
    @Resource
    SimpleJobLauncher simpleJobLauncher;

    public JobParameters jobParameters;
    @Autowired
    Job importJob;

    @Test
    public void  testJob() throws JobParametersInvalidException, JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException {
        jobParameters = new JobParametersBuilder().addLong("time", System.currentTimeMillis()).toJobParameters();
        simpleJobLauncher.run(importJob, jobParameters);
    }
}

5 在开始上面的配置之前,还要创建项目,集成 Mybatis ,导入数据库表等。这里就不详述了

6 spring batch 是一个大数据量的批处理框架,但是并没有提供 定时执行的能力,这个还要依靠外部框架,比如 quartz,elastic job等,接下来还会在项目中集成 elastc job 这个框架,elastic job 是一个分布式的定时器框架,在分布式系统中可以控制他单机或者多机跑。

7 参考的 git项目地址为:[email protected]:ds245486410/hellen-spring-batch.git

在上文中有什么没有疑问的,可以看看项目的内容。

你可能感兴趣的:(java开发)