Reputation: 1868
I'm running a Spring Batch app that inserts a few thousand rows in my Postgresql database per batch. Every now & then, for no apparent reason, we get the following exception:
org.springframework.orm.jpa.JpaSystemException: nested exception is javax.persistence.PersistenceException at ...
There is nothing to tell us what the PersistenceException
is. It doesn't always happen, and it does not occur in the same place. I've been researching common causes of this exception and have tried everything:
JPAVendorAdapter
which is supposed to give better error messages (it doesn't)JPASystemException
, but when the execution got there, there was nothing in the stacktrace to point to what went wrong.Does anyone have any other ideas? I don't even know what code to show here, because I don't know where the error stems from, be it a bad configuration, service, or repository. I would really appreciate any more ideas!
The full stacktrace is below:
com.company.common.exception.ERDException: org.springframework.orm.jpa.JpaSystemException:
nested exception is javax.persistence.PersistenceException
at com.company.ingest.delegate.BaseDelegate.insertRecords(BaseDelegate.java:537)
at com.company.ingest..delegate.Delegate.writeResult(Delegate.java:164)
at com.company.ingest.job.AbstractBaseJob.insertReturnsRecords(AbstractBaseJob.java:678)
at com.company.ingest.job.PerfReturnsWriter.processData(PerfReturnsWriter.java:115)
at com.company.ingest.job.PerfReturnsWriter.write(PerfReturnsWriter.java:83)
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:498)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
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:213)
at com.sun.proxy.$Proxy201.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.FaultTolerantChunkProcessor$3.doWithRetry(FaultTolerantChunkProcessor.java:328)
at org.springframework.retry.support.RetryTemplate.doExecute(RetryTemplate.java:287)
at org.springframework.retry.support.RetryTemplate.execute(RetryTemplate.java:211)
at org.springframework.batch.core.step.item.BatchRetryTemplate.execute(BatchRetryTemplate.java:217)
at org.springframework.batch.core.step.item.FaultTolerantChunkProcessor.write(FaultTolerantChunkProcessor.java:420)
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: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 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Upvotes: 3
Views: 1367
Reputation: 1661
The problem is that you are handling the exception incorrectly in a way that suppresses the root cause (or that you declared your exception class to suppress any exception-stacktraces that were passed in). The actual exception that is thrown is your own business exception.
You didn't post the content of your method: com.company.ingest.delegate.BaseDelegate.insertRecords(BaseDelegate.java:537) but based on what you posted, I am going to guess that the method looks something like this:
public void insertRecords(...) {
try {
repository.save(...);
} catch (Exception exception) {
throw new com.company.common.exception.ERDException(exception.toString());
}
}
This would explain why the exception that is thrown and logged does not contain any meaningful information. The exception that you caught does contain a message itself. It wraps another exception that (we assume) contains the root cause.
If my assumption about your method is correct, then the following change would provide the root cause the next time the error occurs, assuming your exception passes the parameters along to the superclass (all the way to Throwable):
public void insertRecords(...) {
try {
repository.save(...);
} catch (Exception exception) {
throw new com.company.common.exception.ERDException("Unable to insert record", exception);
}
}
Upvotes: 1
Reputation: 1771
Use the exception methods documented here to troubleshoot the root cause for the exception in the stack trace of yours.
Upvotes: 0