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

Spring批处理-JdbcCursorItemReader使用大型MySQL表抛出OutOfMemoryError

戚森
2023-03-14

我正在编写一个程序,使用Spring Batch处理MySQL数据库表中的7637064行。我成功地处理了较小的表,但当JdbcCursorItemReader尝试打开光标时,该表中的大量行导致了OutOfMemoryError异常。

我可能可以通过向它扔一个更大的Xmx来解决这个问题,但在我看来,Spring Batch应该有办法处理这个问题,我可能只是缺少一个关键的配置部分。

Spring批配置:

  <job id="reportJob" xmlns="http://www.springframework.org/schema/batch">
    <step id="largeTableTransfer">
      <tasklet>
        <chunk reader="largeTableReader" processor="largeTableTransformer" writer="largeTableWriter"
          commit-interval="10" />
      </tasklet>
    </step>
  </job>

  <bean id="largeTableReader" class="org.springframework.batch.item.database.JdbcCursorItemReader">
    <property name="dataSource" ref="inputDataSource" />
    <property name="sql" value="select * from largeTable" />
    <property name="rowMapper">
      <bean class="myproject.reader.largeTableRowMapper" />
    </property>
  </bean>
  <bean id="largeTableTransformer" class="myproject.transformer.LargeTableTransformer" />
  <bean id="largeTableWriter" class="myproject.writer.JdbcLargeTableWriter">
    <property name="dataSource" ref="outputDataSource" />
  </bean>

在JdbcCursorItemReader上设置fetchSize似乎没有效果。唯一允许它运行到完成的是将maxRows设置为一个较小的数字,但随后只处理该数量的行。

相关堆栈跟踪:

2012-11-21 11:25:29,931 DEBUG [org.springframework.batch.core.repository.dao.JdbcStepExecutionDao] - <Truncating long message before update of StepExecution, original message is: java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Arrays.java:2734)
    at java.util.ArrayList.ensureCapacity(ArrayList.java:167)
    at java.util.ArrayList.add(ArrayList.java:351)
    at com.mysql.jdbc.MysqlIO.readSingleRowSet(MysqlIO.java:2821)
    at com.mysql.jdbc.MysqlIO.getResultSet(MysqlIO.java:467)
    at com.mysql.jdbc.MysqlIO.readResultsForQueryOrUpdate(MysqlIO.java:2510)
    at com.mysql.jdbc.MysqlIO.readAllResults(MysqlIO.java:1746)
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2135)
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2542)
    at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1734)
    at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:1885)
    at org.apache.commons.dbcp.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement.java:93)
    at org.springframework.batch.item.database.JdbcCursorItemReader.openCursor(JdbcCursorItemReader.java:125)
    at org.springframework.batch.item.database.AbstractCursorItemReader.doOpen(AbstractCursorItemReader.java:401)
    at org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader.open(AbstractItemCountingItemStreamItemReader.java:134)
    at org.springframework.batch.item.support.CompositeItemStream.open(CompositeItemStream.java:93)
    at org.springframework.batch.core.step.tasklet.TaskletStep.open(TaskletStep.java:301)
    at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:192)
    at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:135)
    at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:61)
    at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:60)
    at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:144)
    at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:124)
    at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:135)
    at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:293)
    at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:120)
    at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:48)
    at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:114)
    at ifpress.ams2amx.ExampleJobConfigurationTests.testLaunchJob(ExampleJobConfigurationTests.java:32)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

共有1个答案

邹祺
2023-03-14

MySql JDBC驱动程序中存在一个问题,它会导致将整个数据集加载到内存中,而不考虑传递给语句创建方法的参数。看见http://dev.mysql.com/doc/refman/5.0/en/connector-j-reference-implementation-notes.html了解如何正确打开光标。

我是这样做的:

<bean class="org.springframework.batch.item.database.JdbcCursorItemReader">
  <property name="verifyCursorPosition" value="false" />
   <property name="dataSource" ref="remoteDataSource" />
   <property name="rowMapper">
     <bean class="org.springframework.jdbc.core.SingleColumnRowMapper" />
   </property>
   <property name="fetchSize">
     <util:constant static-field="java.lang.Integer.MIN_VALUE" />
   </property>
   <property name="sql">
     <value>SELECT foo, bar FROM baz</value>
  </property>
</bean>
 类似资料:
  • 我在Spring Batch中遇到了一个问题,这通常很简单。 我有多个步骤,面向块处理。对于每个步骤,我都想使用相同的ItemReader。 这是我的步骤宣言: 我的请求有一些参数,我想用准备状态设置器替换它们。 所以我的意图是为每个bean创建多个bean(对于每个步骤),以便为每个bean调用特定的准备语句。 我有以下错误: 我做错了什么?如果你需要更多的细节,请告诉我。 谢谢你的帮助。

  • 在Spring batch中(请参见https://docs.Spring.io/spring-batch/3.0.x/reference/html/metadataschema.html),有六个表: batch_job_execution batch_job_execution_context batch_job_execution_params batch_job_instance batc

  • 问题内容: 我有一些Python代码可以执行一个外部应用程序,当该应用程序的输出量很少时,它可以很好地运行,但是在有大量输出时,它会挂起。我的代码如下: 文档中有一些注释似乎表明了潜在的问题。等待中,有: 警告:如果子进程向或管道生成足够的输出,从而阻塞等待OS管道缓冲区接受更多数据的输出,则将死锁。使用避免这种情况。 尽管进行了交流,但我发现: 注意读取的数据缓存在内存中,因此,如果数据大小很大

  • 我正在处理包含数据库中多个记录列表的。 我应该如何指定处理每个子列表的块大小? 感谢您的帮助,提前谢谢。

  • 问题内容: 我有一个使用JDBC的Java应用程序,该应用程序每天在服务器上运行一次,并与也在同一服务器上运行的MySQL数据库(v5.5)进行交互。该应用程序正在查询并遍历表中的 所有 行。 该表目前很小(约5000行),但将无限期地增长。我的服务器内存有限,我不认为应用程序的内存消耗不确定。 如果我在运行查询之前使用过,我不清楚这里发生了什么。例如,如果我使用类似: 这是如何适当控制潜在的大型

  • 我有一个使用JDBC的Java应用程序,它每天在我的服务器上运行一次,并与同样在同一服务器上运行的MySQL数据库(v5.5)交互。该应用程序正在查询和遍历表中的所有行。 该表目前相当小(约5000行),但将无限期地继续增长。我的服务器内存有限,我不喜欢应用程序内存消耗不确定的想法。 如果我使用在运行查询之前,我不清楚这里发生了什么。例如,如果我使用以下内容: 这是如何适当地控制潜在的大型sele