我有一个使用分区步骤的 Spring Batch (v2.2.1) 作业。此分区步骤使用JpaPagingItemReader
对返回的结果进行分页来访问数据库。分区在本地 JVM 中使用 Spring 的SimpleAsyncTaskExecutor
.
假设数据库操作需要“长”时间(这里的长意味着比处理时间长),我的问题归结为:确定最大数据库连接数以防止分区阻塞等待的好的经验法则是什么连接?
我最初的想法是我应该至少有gridSize
数据库连接,以便每个分区步骤都有自己的数据库连接可以使用,再加上一些额外的用于 Spring 可能具有的任何开销(我知道这不是一个非常科学的衡量标准......因此问题) .
我在此配置中观察到的是,我的分区步骤将花费大量时间阻塞等待数据库连接。
这是一个使用partitionJdbcJob
spring-batch-samples 来说明场景的示例:
数据源:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.user}" />
<property name="password" value="${jdbc.password}" />
<property name="validationQuery" value=""/>
<property name="testWhileIdle" value="false"/>
<property name="maxActive" value="7"/>
</bean>
作业、分区程序和分区步骤:
<job id="partitionJdbcJob" xmlns="http://www.springframework.org/schema/batch">
<step id="step">
<partition step="step1" partitioner="partitioner">
<handler grid-size="5" task-executor="taskExecutor"/>
</partition>
</step>
</job>
<bean id="partitioner" class="org.springframework.batch.sample.common.ColumnRangePartitioner">
<property name="dataSource" ref="dataSource" />
<property name="table" value="CUSTOMER" />
<property name="column" value="ID" />
</bean>
<bean id="taskExecutor" class="org.springframework.core.task.SimpleAsyncTaskExecutor" />
<step id="step1" xmlns="http://www.springframework.org/schema/batch">
<tasklet>
<chunk writer="itemWriter" reader="itemReader" processor="itemProcessor" commit-interval="100" />
<listeners>
<listener ref="fileNameListener" />
</listeners>
</tasklet>
</step>
<bean id="itemReader" class="org.springframework.batch.item.database.JpaPagingItemReader" scope="step">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
<property name="pageSize" value="100"/>
<property name="queryProvider">
<bean class="my.example.QueryProvider" scope="step">
<property name="minDefaultId" value="#{stepExecutionContext[minValue]}" />
<property name="maxDefaultId" value="#{stepExecutionContext[maxValue]}" />
</bean>
</property>
</bean>
鉴于上述配置,以下是重要的数字:
- 网格大小:5
- 最大活动连接数:7
- 提交间隔:100
- 页面大小:100
使用此配置,我希望分区程序可以分区 5 个步骤。每个步骤都应该能够拥有自己的数据库连接(因为应用程序最多允许 7 个......这似乎很多)。然后每一步将一次翻阅它的工作 100 条记录,在每页之后提交工作。
但是,我观察到(使用 jconsole)执行我的分区步骤的线程会经常被阻塞以等待数据库连接。如果我的最大活动连接数大于我的网格大小,他们为什么会阻止?