JpaPagingItemReader事务问题:StaleObjectStateException

时间:2019-03-27 11:39:44

标签: java spring jpa spring-batch

下面是我的春季批处理块配置

  1. Reader-使用JpaPagingItemReader读取实体
  2. 处理器-处理读取器返回的实体,并根据不同的条件更新同一实体中的某些字段
  3. Writer-调用entitymanager.merge(entity)以合并在处理器中完成的更改的简单逻辑
<batch:step id="matchUploadedTradesWithUbsTrades"  next="updateJobStatus">
    <batch:tasklet>
    <batch:chunk
            reader="matchingDatasetReader"
            processor="matchingDatasetProcessor"
            writer="matchingDatasetWriter"
            commit-interval="10"
    />
    </batch:tasklet>
    <batch:listeners>
        <batch:listener ref="stepExecutionListener" />
    </batch:listeners>
 </batch:step>

<bean id="matchingDatasetReader" class="com.batch.reader.MatchingJobDatasetReader" scope="job">
    <property name="entityManagerFactory" ref="entityManagerFactoryBean" />
    <property name="queryString" value="#{ T(com.batch.jpa.entity.Entity).QUERY_FIND_RECORDDS}"/>
    <property name="pageSize" value="10" />
</bean>

<bean id="matchingDatasetProcessor" class="com.batch.processor.MatchingJobDatasetProcessor" scope="job"/>

<bean id="matchingDatasetWriter" class="com.batch.writer.MatchingJobDatasetWriter" scope="job"/>

在以下两种情况下,我遇到JpaPagingItemReader的问题。

场景1 –我在批处理配置中设置的commit-interval(10)少于实体中的记录总数(15个记录),并调用了entitymanager.merge(entity)在作家中被注释 commit-interval = 10 总记录= 15

观察:记录正在数据库中更新。这样做的原因是,当commit-interval小于记录数时,JpaPagingItemReader会在读取下一批批处理之前将entitymanager.flush调用,而不提交entitymanager.merge方法。

场景2 –我在批处理配置中设置的commit-interval少于客户交易中的记录总数,并在writer中调用了更新方法 commit-interval = 10 总记录= 15

观察:我收到StaleObjectStateException,因为实体已经通过调用entitymanager.writer进行更新。merge,Reader会尝试刷新writer所做的更改。

javax.persistence.OptimisticLockException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.batch.jpa.entity.Client#29657]
        at org.hibernate.jpa.spi.AbstractEntityManagerImpl.wrapStaleStateException(AbstractEntityManagerImpl.java:1785)
        at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1705)
        at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1677)
        at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1683)
        at org.hibernate.jpa.spi.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:1338)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:497)
        at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:366)
        at com.sun.proxy.$Proxy76.flush(Unknown Source)
        at org.springframework.batch.item.database.JpaPagingItemReader.doReadPage(JpaPagingItemReader.java:199)
        at org.springframework.batch.item.database.AbstractPagingItemReader.doRead(AbstractPagingItemReader.java:108)
        at org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader.read(AbstractItemCountingItemStreamItemReader.java:88)
        at sun.reflect.GeneratedMethodAccessor42.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:497)
        at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
        at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:132)
        at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:120)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
        at com.sun.proxy.$Proxy85.read(Unknown Source)
        at org.springframework.batch.core.step.item.SimpleChunkProvider.doRead(SimpleChunkProvider.java:91)
        at org.springframework.batch.core.step.item.SimpleChunkProvider.read(SimpleChunkProvider.java:157)
        at org.springframework.batch.core.step.item.SimpleChunkProvider$1.doInIteration(SimpleChunkProvider.java:116)
        at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:374)
        at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215)
        at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:144)
        at org.springframework.batch.core.step.item.SimpleChunkProvider.provide(SimpleChunkProvider.java:110)
        at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:69)
        at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:406)
        at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:330)
        at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:131)
        at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:272)
        at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:81)
        at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:374)
        at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215)
        at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:144)
        at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:257)
        at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:200)
        at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:148)
        at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:64)
        at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:67)
        at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:169)
        at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:144)
        at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:134)
        at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:306)
        at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:135)
        at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:49)
        at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:128)
Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.batch.jpa.entity.Client#29657]
        at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:2541)
        at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3285)
        at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:3183)
        at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3525)
        at org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:158)
        at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:453)
        at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:345)
        at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:350)
        at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:56)
        at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1218)
        at org.hibernate.jpa.spi.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:1335)
        ... 61 more

我也尝试设置自定义块策略,但是观察到的行为相同。

有人可以帮我处理这两种情况吗?

0 个答案:

没有答案