有没有办法只为特定作业跳过 Spring Batch 的持久元数据?

Posted

技术标签:

【中文标题】有没有办法只为特定作业跳过 Spring Batch 的持久元数据?【英文标题】:Is there a way to skip persisting metadata for Spring Batch only for particular jobs? 【发布时间】:2020-02-20 12:28:05 【问题描述】:

有几个示例说明我们如何使用 Spring Batch 而不将元数据持久化到数据库中。以下是有关此事的一些示例和相关问题:

Spring-Batch without persisting metadata to database?

How to avoid Spring batch persistence of metadata in DB

Spring Batch - How to prevent batch from storing transactions in DB

Spring boot + spring batch without DataSource

但是我有一个稍微不同的用例:我有一些每隔一小时左右运行一次的作业,我想将其中的元数据保存到我的数据库中(例如,创建报告、运行一些测试,这两者都可能略有不同)处理量大)。我有一些其他类型的作业每分钟左右运行一次(例如,解锁由于重复输入错误密码等而被锁定的用户帐户),这些作业不涉及太多处理,而是一个简单的 sql 查询。

问题分为两部分:

    有没有办法将第一类作业(例如报告处理)的元数据保留在数据库中,而对第二类作业(例如解锁用户帐户)完全不使用数据库持久性?

    或者,甚至将 Spring Batch 用于第二种类型的作业是否过大/根本不需要?带有@Scheduled 注解的方法就够了吗?

【问题讨论】:

【参考方案1】:
    有没有办法将第一类作业(例如报告处理)的元数据保留在数据库中,而对第二类作业(例如解锁用户帐户)完全不使用数据库持久性?

这是配置问题。您可以使用 Spring profiles 作为数据源。这个想法是定义一个持久数据源和一个内存数据源。然后像往常一样使用数据源配置所有作业,并在运行时使用正确的配置文件运行它们。这是一个简单的例子:

import javax.sql.DataSource;

import com.zaxxer.hikari.HikariDataSource;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;

@Configuration
@EnableBatchProcessing
public class JobsConfiguration 

    @Bean
    public Job job1() 
        return null;
    

    @Bean
    public Job job2() 
        return null;
    

    @Bean
    @Profile("in-memory")
    public DataSource embeddedDataSource() 
        return new EmbeddedDatabaseBuilder()
                .setType(EmbeddedDatabaseType.HSQL)
                .addScript("/org/springframework/batch/core/schema-hsqldb.sql")
                .build();
    

    @Bean
    @Profile("persistent")
    public DataSource persistentDataSource() 
        HikariDataSource hikariDataSource = new HikariDataSource();
        // TODO configure datasource
        return hikariDataSource;
    

如果您使用-Dspring.profiles.active=in-memory 运行您的应用程序,那么在您的应用程序上下文中将只有嵌入的数据源bean,它将被@EnableBatchProcessing 自动配置的作业存储库使用。

    或者,甚至将 Spring Batch 用于第二种类型的作业是否过大/根本不需要?只需一个带有@Scheduled 注解的方法就足够了吗?

which do not involve much of processing but a simple sql query:如果它是一个简单的 sql 查询并且您不需要保留元数据,那么最好使用带有 @Scheduled 注释的方法,该方法使用 jdbcTemplate 来运行查询。

【讨论】:

感谢您的回答。我需要一个关于如何告诉 Spring 为不同的工作使用不同的数据源的示例。可用配置仅允许我对所有作业使用单个数据源。我看不到为每个作业配置数据源的方法。 how to tell Spring to use different datasources for different jobs. : 使用配置文件的重点是使用单个数据源配置所有作业(不必为每个作业配置自己的数据源)并让spring根据在运行时选择的配置文件。我在答案中添加了一个示例。 "...然后像往常一样使用数据源配置所有作业..." 这与我想要实现的目标完全相反。你误解了这个问题。在同一个应用程序中,我有不止一项工作,我想使用不同的数据源运行。 不,我收到了你的问题,我的示例故意包含 2 个工作。如果您使用 spring boot,您可以使用--spring.batch.job.names=job1 --spring.profiles.active=in-memory,您的 job1 将使用内存数据源运行。如果您不使用 spring boot,您仍然可以将配置文件添加到作业 bean 以及告诉 spring 哪个作业应该使用哪个数据源。 但只有我的job1 可以运行吗?对于job2,我必须拥有另一个应用程序实例。【参考方案2】:

关于 Mahmoud Ben Hassine 的建议,我是如何实现我正在寻找的东西的(删除 @EnableBatchProcessing,对于一些不相关的问题 - see here):

我有两个配置类:

@Configuration
public class SpringBatchConfiguration extends DefaultBatchConfigurer 

    @Inject public SpringBatchConfiguration(DataSource dataSource) 
        super(dataSource);
    

    @Bean(name = "persistentJobLauncher")
    public JobLauncher jobLauncher() throws Exception 
        return super.createJobLauncher();
    

    @Bean
    @Primary
    public StepBuilderFactory stepBuilderFactory() 
        return new StepBuilderFactory(super.getJobRepository(), super.getTransactionManager());
    

    @Bean
    @Primary
    public JobBuilderFactory jobBuilderFactory()
        return new JobBuilderFactory(super.getJobRepository());
    

    @Bean
    public JobExplorer jobExplorer() 
        return super.getJobExplorer();
    

    @Bean
    public JobRepository jobRepository() 
        return super.getJobRepository();
    

    @Bean
    public ListableJobLocator jobLocator() 
        return new MapJobRegistry();
    

和内存中的一个:

@Configuration
public class SpringInMemoryBatchConfiguration extends DefaultBatchConfigurer 

    @Inject public SpringInMemoryBatchConfiguration() 
    

    @Bean(name = "inMemoryJobLauncher")
    public JobLauncher inMemoryJobLauncher() throws Exception 
        return super.createJobLauncher();
    

    @Bean(name = "inMemoryStepBuilderFactory")
    public StepBuilderFactory stepBuilderFactory() 
        return new StepBuilderFactory(super.getJobRepository(), super.getTransactionManager());
    

    @Bean(name = "inMemoryJobBuilderFactory")
    public JobBuilderFactory inMemoryJobBuilderFactory()
        return new JobBuilderFactory(super.getJobRepository());
    

当我想开始一项“持久性”工作时,我使用@Qualifier(value = "persistentJobLauncher") JobLauncher launcher 并开始一项“内存中”工作:@Qualifier(value = "inMemoryJobLauncher") JobLauncher launcher

【讨论】:

以上是关于有没有办法只为特定作业跳过 Spring Batch 的持久元数据?的主要内容,如果未能解决你的问题,请参考以下文章

json.dumps“跳过”特定键?

perl foreach 循环跳过特定文件夹下特定文件的迭代

禁用计划作业

跳过创建特定表 [Spring] [Hibernate]

Spring boot:如何跳过特定端点的基本身份验证

在情节提要中,您可以只为一台设备编辑布局吗?