Spring Framrwork

MybatisBatchWriter 오류 해결방법

gregorio 2018. 2. 3. 09:20

Spring Batch 수행 시 

Batch execution returned invalid results. Expected 1 but number of BatchResult objects returned was 2 오류가 발생하는 경우에 다음과 같이 조치한다.



■ 원인

하나의 Job에 Multi Step을 정의하고, ItemReader에서 MyBatisPagingItemReader ItemProcessor에서 Dao를 이용하여 DB에서 Insert 한 후 ItemWriter에서 MyBatisBatchItemWriter를 적용하는 경우에 발생함


하나의 Job에 단일 Step이 있는 경우에는 오류가 발생하지 않는다.



■ 오류 내역


09:11:40.975 [main] DEBUG o.s.transaction.support.TransactionTemplate | Initiating transaction rollback on application exception

org.springframework.dao.InvalidDataAccessResourceUsageException: Batch execution returned invalid results. Expected 1 but number of BatchResult objects returned was 2

at org.mybatis.spring.batch.MyBatisBatchItemWriter.write(MyBatisBatchItemWriter.java:136)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

at java.lang.reflect.Method.invoke(Method.java:606)

at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)

at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)

at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)

at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:133)

at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:121)

at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)

at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)

at com.sun.proxy.$Proxy14.write(Unknown Source)

at org.springframework.batch.core.step.item.SimpleChunkProcessor.writeItems(SimpleChunkProcessor.java:175)

at org.springframework.batch.core.step.item.SimpleChunkProcessor.doWrite(SimpleChunkProcessor.java:151)

at org.springframework.batch.core.step.item.SimpleChunkProcessor.write(SimpleChunkProcessor.java:274)

at org.springframework.batch.core.step.item.SimpleChunkProcessor.process(SimpleChunkProcessor.java:199)

at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:75)

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:133)

at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:271)

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:50)

at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:128)

at cmn.util.spring.batch.runner.BaseCmdRunner.start(BaseCmdRunner.java:278)

at sehati.batch.sample.runner.SampleDB2FileJobRunner.main(SampleDB2FileJobRunner.java:162) 

  


■ MyBatisBatchItemWriter Code


MyBatisBatchItemWriter Class의 136라인에 result Size를 Check하는 로직이 들어있다. 

result.size() 가 1 이 아닌 경우 Exception을 Throw하고 있다.


      if (assertUpdates) {

        if (results.size() != 1) {

          throw new InvalidDataAccessResourceUsageException("Batch execution returned invalid results. " +

              "Expected 1 but number of BatchResult objects returned was " + results.size());

        }

 


■ 해결방법


<bean id="stepWriter1" class="org.mybatis.spring.batch.MyBatisBatchItemWriter" scope="step">

<property name="sqlSessionFactory" ref="sqlSession" />

<property name="statementId" value="batch.sample.Message.insMessage1" />

<property name="assertUpdates" value="false" />

</bean> 


MyBatisItemWriter의 속성 assertUpdates를 false로 하면 오류없이 정상적으로 처리된다.