簡體   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