繁体   English   中英

Spring 批处理作业未在 Spring 引导中调用

[英]Spring Batch job not being called in Spring Boot

我正在尝试运行 Spring 批处理作业,该作业接收 CSV 文件并将其写入 HSQL 嵌入式数据库。 当 CSV 的每一行被添加到数据库时,我的程序应该记录,但事实并非如此。运行时我没有收到任何错误,但我知道作业没有被调用,因为它没有将任何内容记录到我的控制台中。

这是我的文件系统

这是我的 BatchConfig.java(定义批处理作业)

package io.davidwilliford.wcdashboard.data;

import javax.sql.DataSource;

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.job.builder.JobBuilder;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider;
import org.springframework.batch.item.database.JdbcBatchItemWriter;
import org.springframework.batch.item.database.builder.JdbcBatchItemWriterBuilder;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder;
import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.transaction.PlatformTransactionManager;

import io.davidwilliford.wcdashboard.model.Match;

/**
 * Configuration class for our Batch I/O
 * 
 * Reads, Processes and Writes from CSV file
 * Called for every line in our CSV
 */

@Configuration
@EnableBatchProcessing
@ComponentScan("io.davidwilliford")
public class BatchConfig {

    // includes EVERY field of CSV file
    private final String[] FIELD_NAMES = new String[] {
            "match", "dayofweek", "match_time", "home_team", "away_team", "home_xg", "away_xg", "score", "attendance",
            "venue", "referee", "home_formation", "away_formation", "home_captain", "away_captain", "home_manager",
            "away_manager", "home_possession", "away_possession", "home_completed_passes", "home_attempted_pases",
            "away_completed_passes", "away_attempted_pases", "home_sot", "away_sot", "home_total_shots",
            "away_total_shots", "home_saves", "away_saves", "home_fouls", "away_fouls", "home_corners", "away_corners",
            "home_crosses", "away_crosses", "home_touches", "away_touches", "home_tackles", "away_tackles",
            "home_interceptions", "away_interceptions", "home_aerials_won", "away_aerials_won", "home_clearances",
            "away_clearances", "home_offsides", "away_offsides", "home_gks", "away_gks", "home_throw_ins",
            "away_throw_ins", "home_long_balls", "away_long_balls"
    };

    /**
     * Reader
     * 
     * Reads from CSV file
     * And turns into MatchInput object
     */
    @Bean
    public FlatFileItemReader<MatchInput> reader() {
        return new FlatFileItemReaderBuilder<MatchInput>()
                .name("MatchItemReader")
                .resource(new ClassPathResource("match-data.csv"))
                .linesToSkip(1)
                .delimited()
                .names(FIELD_NAMES)
                .fieldSetMapper(new BeanWrapperFieldSetMapper<MatchInput>() {
                    {
                        setTargetType(MatchInput.class);
                    }
                })
                .build();
    }

    /**
     * Processor
     * 
     * Takes in MatchInput objects and makes Match objects
     * Is encapsulated into its own class
     */
    @Bean
    public MatchDataProcessor processor() {
        return new MatchDataProcessor();
    }

    /**
     * Writer
     * 
     * Writes the information into Match objects
     */
    @Bean
    public JdbcBatchItemWriter<Match> writer(DataSource dataSource) {
        return new JdbcBatchItemWriterBuilder<Match>()
                .itemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>())
                .sql("INSERT INTO matches (id, dayofweek, match_time, home_team, away_team, home_score, away_score, attendance, venue, referee, home_captain, away_captain,  home_manager, away_manager, home_total_shots, away_total_shots) "
                        +
                        "VALUES (:id, :dayofweek, :match_time, :home_team, :away_team, :home_score, :away_score, :attendance, :venue, :referee, :home_captain, :away_captain, : home_manager, :away_manager, :home_total_shots, :away_total_shots)")
                .dataSource(dataSource)
                .build();
    }

    /**
     * Create a Job whose steps are to Read, Process and Write
     */
    @Bean
    public Job importUserJob(JobRepository jobRepository, JobCompletionNotificationListener listener, Step step1) {
        return new JobBuilder("importUserJob", jobRepository)
                .incrementer(new RunIdIncrementer())
                .listener(listener)
                .flow(step1)
                .end()
                .build();
    }

    /**
     * This is the step for the above job
     * Calls reader, processor and writer (written above)
     */
    @Bean
    public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager,
            JdbcBatchItemWriter<Match> writer) {
        return new StepBuilder("step1", jobRepository)
                .<MatchInput, Match>chunk(10, transactionManager)
                .reader(reader())
                .processor(processor())
                .writer(writer)
                .build();
    }
}

这是我的 MatchInput.java class

package io.davidwilliford.wcdashboard.data;

/**
 * Class for match input
 * 
 * Match will work as our Id
 * In total, there are 63 matches
 */

public class MatchInput {

    /**
     * Class attributes
     */
    private String match;
    private String dayofweek;
    private String match_time;
    private String home_team;
    private String away_team;
    private String home_xg;
    private String away_xg;
    private String score;
    private String attendance;
    private String venue;
    private String referee;
    private String home_formation;
    private String away_formation;
    private String home_captain;
    private String away_captain;
    private String home_manager;
    private String away_manager;
    private String home_possession;
    private String away_possession;
    private String home_completed_passes;
    private String home_attempted_pases;
    private String away_completed_passes;
    private String away_attempted_pases;
    private String home_sot;
    private String away_sot;
    private String home_total_shots;
    private String away_total_shots;
    private String home_saves;
    private String away_saves;
    private String home_fouls;
    private String away_fouls;
    private String home_corners;
    private String away_corners;
    private String home_crosses;
    private String away_crosses;
    private String home_touches;
    private String away_touches;
    private String home_tackles;
    private String away_tackles;
    private String home_interceptions;
    private String away_interceptions;
    private String home_aerials_won;
    private String away_aerials_won;
    private String home_clearances;
    private String away_clearances;
    private String home_offsides;
    private String away_offsides;
    private String home_gks;
    private String away_gks;
    private String home_throw_ins;
    private String away_throw_ins;
    private String home_long_balls;
    private String away_long_balls;
   
    // purposely left out getters and setters since they arent important 

}

这是我的比赛。java model class

package io.davidwilliford.wcdashboard.model;

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

/**
 * This is the model class for all of our matches
 * 
 * @Entity creates a table with this class
 */
@Entity
@Table(name = "matches")
public class Match {

    /**
     * Class attributes
     */

    @Id
    private int id;
    private String dayofweek;
    private String match_time;
    private String home_team;
    private String away_team;
    private String home_score;
    private String away_score;
    private String attendance;
    private String venue;
    private String referee;
    private String home_captain;
    private String away_captain;
    private String home_manager;
    private String away_manager;
    private String home_total_shots;
    private String away_total_shots;

    /**
     * toString method
     */

    @Override
    public String toString() {
        return "Home Team: " + this.home_team + ", Away Team: " + this.away_team;
    }

    /**
     * Getters and Setters
     */

    public long getId() {

}

这是我的 JobCompleteNotificationListener.java class

这个 class 应该在完成后记录主队和客队的名字。

package io.davidwilliford.wcdashboard.data;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobExecutionListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

@Component
public class JobCompletionNotificationListener implements JobExecutionListener {

    private static final Logger log = LoggerFactory.getLogger(JobCompletionNotificationListener.class);

    private final JdbcTemplate jdbcTemplate;

    @Autowired
    public JobCompletionNotificationListener(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    /**
     * After job is complete,
     * Return and print the 2 teams, and the time
     */
    @Override
    public void afterJob(JobExecution jobExecution) {
        if (jobExecution.getStatus() == BatchStatus.COMPLETED) {
            log.info("!!! JOB FINISHED! Time to verify the results");

            jdbcTemplate.query("SELECT home_team, away_team FROM match",
                    (rs, row) -> "Home Team: " + rs.getString(1) + " Away Team: "
                            + rs.getString(2))
                    .forEach(str -> System.out.println(str));
        }
    }
}

当我运行 spring 引导应用程序时,我的控制台中没有任何记录。 希望这是足够的信息,如果需要我可以提供更多。 真诚地感谢任何愿意提供帮助的人。

该程序旨在接收 CSV(2022 世界杯信息)并将其嵌入到 Spring 启动应用程序内的 HSQL 嵌入式数据库中。 我已按照官方 Spring 引导指南完成 Spring 批处理作业(此处: https://spring.io/guides/gs/batch-processing/ ),但到目前为止运气不佳。

请检查“afterJob”方法是否正在执行/发生其他状态,如 BatchStatus。 弃?

 public void afterJob(JobExecution jobExecution) {
        if (jobExecution.getStatus() == BatchStatus.ABANDONED) {
...

请尝试删除注释@EnableBatchProcessing

当您从 jakarta 命名空间导入时,我假设您使用的是 Spring Boot 3 和 Spring Batch 5。

在 Spring Boot 3 中,Spring Batch 注释@EnableBatchProcessing现在具有禁用 Spring Batch 自动配置的效果。 如果您希望公开的Job在应用程序启动时自动启动,那么您缺少的就是这种自动配置。

@Henning 非常感谢! 我很难找到这个,因为https://docs.spring.io/spring-boot/docs/3.0.1/reference/html/howto.html#howto.batch.running-jobs-on-startup仍然声明使用@启用批处理。 但是, https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Migration-Guide显然不鼓励使用@EnableBatchProcessing。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM