当前位置: 首页 > 知识库问答 >
问题:

为什么Spring批处理为每个线程使用1个数据库连接?

南宫俊喆
2023-03-14

为什么Spring批处理为每个线程使用1个数据库连接?

堆栈:

    null

数据源配置:

  • BATCDB(postgres)
  • READDB(oracle)
  • 写B(后置)

每个数据源都使用HikariCP,每个数据源默认有10个连接。

core-pool-size: 10
max-pool-size: 10
throttle-limit: 10

作业-1配置/ThreadPoolTaskExecutor:(通过application.yml设置池大小和节流限制)

@Bean
public Step job1Step() {
    return stepBuilderFactory.get("job1Step")
            .<ReadModel, WriteModel>chunk(chunkSize)
            .reader(itemReader())
            .processor(compositeProcessor())
            .writer(itemWriter())
            .faultTolerant()
            .taskExecutor(job1TaskExecutor())
            .throttleLimit(throttleLimit)
            .build();
}

@Bean
public ThreadPoolTaskExecutor job1TaskExecutor() {
     ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
     pool.setCorePoolSize(poolSize);
     pool.setMaxPoolSize(maxPoolSize);
     pool.setWaitForTasksToCompleteOnShutdown(false);
     return pool;
 }

@Bean
@StepScope
public Job1ItemReader job1ItemReader() {
    return new Job1ItemReader(readdb, pageSize);
}

Job1-ItemReader的缩写代码

public class Job1ItemReader extends JdbcPagingItemReader<ReadModel> {
...
}

ThreadeXecutor-2:

core-pool-size: 5
max-pool-size: 5
throttle-limit: 5
@Bean
public Step job2Step() throws Exception {
    return stepBuilderFactory.get("job2Step")
            .<ReadModel2, WriteModel2>chunk(chunkSize)
            .reader(job2ItemReader())
            .processor(job2CompositeProcessor())
            .writer(job2ItemWriter())
            .faultTolerant()
            .taskExecutor(job2TaskExecutor())
            .throttleLimit(throttleLimit)
            .build();
}

@Bean
public ThreadPoolTaskExecutor job2TaskExecutor() {
    ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
    pool.setCorePoolSize(corePoolSize);
    pool.setMaxPoolSize(maxPoolSize);
    pool.setQueueCapacity(queueCapacity);
    pool.setWaitForTasksToCompleteOnShutdown(false);
    return pool;
}

@Bean
@StepScope
public Job2ItemReader job2ItemReader() {
    return new Job2ItemReader(readdb, pageSize);    
}

Job2-ItemReader的缩写代码

public class Job2ItemReader extends JdbcPagingItemReader<ReadModel2> {
...
}
  • 有2个作业
  • 作业-1是长期运行的(多天)
  • 作业-2通常在一小时或两小时内完成,并且每天按计划运行
  • 作业位于同一个“应用程序”中,运行在同一个JVM上
  • 每个作业都定义了自己的ThreadPoolTaskExecutor

当作业-1运行并且作业-2启动时,作业-2无法获得到readdb的连接。作业-2的批处理读取器引发以下错误。

Caused by: org.springframework.jdbc.support.MetaDataAccessException: Could not get Connection for extracting meta data; nested exception is org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLTransientConnectionException: HikariPool-3 - Connection is not available, request timed out after 30000ms.
at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:339)
at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:366)
at org.springframework.batch.support.DatabaseType.fromMetaData(DatabaseType.java:97)
at org.springframework.batch.item.database.support.SqlPagingQueryProviderFactoryBean.getObject(SqlPagingQueryProviderFactoryBean.java:158)
... 30 common frames omitted
Caused by: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLTransientConnectionException: HikariPool-3 - Connection is not available, request timed out after 30000ms.
at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:80)
at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:326)
... 33 common frames omitted
Caused by: java.sql.SQLTransientConnectionException: HikariPool-3 - Connection is not available, request timed out after 30000ms.
at com.zaxxer.hikari.pool.HikariPool.createTimeoutException(HikariPool.java:666)
at com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:182)
at com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:147)
at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:123)
at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:111)
at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:77)
  • 线程步骤
  • 类似的问题/问题,除了我的事务应该在writedb上,在本例中,hikaripool-3readdb

共有1个答案

邵兴庆
2023-03-14

Spring Batch使用每个线程一个数据库连接的原因(在某些情况下它实际上可以使用更多)是由于事务。Spring事务绑定在一个线程上。Spring批处理中的几乎所有事情都发生在事务中。因此,当您有一个具有单个线程的单个作业时,您最多只使用几个连接。但是,如果您有一个多线程步骤,则期望每个线程至少有一个连接用于事务处理。

 类似资料:
  • 我使用的是Spring Batch 2.1.8。释放我有一个文件,它由一些头信息和一些需要处理的记录组成。 我有一个使用面向块处理的步骤。该步骤包含ItemReader和ItemWriter的实现。ItemReader实现是线程安全的,而ItemWriter不是。 我想在处理(或写入)任何记录之前使用标题信息。在继续使用面向块的处理时,如何确保这一点? 建议的解决方案:一种解决方案可以是编写一个预

  • 我正在通过quartz调度程序调用spring批处理作业,它应该每1分钟运行一次。当作业第一次运行时,成功打开ItemReader并运行作业。但是,当作业尝试第二次运行时,它使用的是第一次运行的相同实例,该实例已经初始化,并接收“java.lang.IllegalStateException:Stream is eignitialized.Close before re-opening”。我已经将

  • 我刚刚用Java8创建了springboot批处理应用程序,我想用Anotation为springbatch表创建一个数据库。 我想我必须创建配置文件,但我不知道怎么做。 @Configuration公共类ConfigBatch{ } 我导入“@ImportResource”生成一个错误,因为在我的java代码中有一个数据源,在我的xml文件中有一个数据源: 我只想在H2数据源中生成spring批

  • 给stackoverflow社区的人们。我正在寻找一些帮助,以解决HikariCP连接池面临的问题。 高级:我正在尝试使用线程池创建多个线程,我的计划是为每个工作线程提供独立于HikariCP的连接,但HikariCP所做的是在多个线程之间共享一个公共连接。我正在使用 以检索DB连接。现在,当我关闭一个连接时,我在其他线程中看到问题,说连接关闭了,线程正在处理的批次记录被丢弃。 以下是我的日志文件

  • context.xml 感谢Sh AntiBhushan

  • 问题内容: 我有这样的代码: 每次尝试访问它时,总会出现恐慌。 像这个: 我以为我可以访问从我设置为全局变量。当我将数据库初始化移动到错误不会出现。 我的代码中哪些部分是错误的? 另外,我是Golang的新手。如果您对如何组织我的代码有任何建议,请告诉我。谢谢.. :) 问题答案: 您的函数中的db变量正在遮盖全局变量。执行此操作时: 它将其分配给新的局部变量db。这是因为它不是来自同一块。根据标