Handling JPA Exception (unique constraint violation)
pimek123 Nov 11, 2010 1:33 PMHello everyone!
I am developing an application based on FUSE ESB 4, which uses JPA 2.0 for the persistence layer, underlying provider is Hibernate. Database used is Oracle 10g.
My application is used to transfer huge amounts of measurements data (physics). I want to avoid situation in which someone inserts the same measurement data twice, thus I put an unique constraint on . This is database's job to prevent duplicated data being stored. It frees me from implementing data duplication avoidance mechanisms in my application, which is fine.
Simplified code for storing data looks as follows:
EntityManager em = entityManagerFactory.createEntityManager();
try {
em.getTransaction().begin();
int howMany = 0;
for (Data data: dataSet) {
data = ...
// ... Data preparation stuff goes here...
// ...
em.persist(data);
// after 20 times, flush
if (howMany++ % 20 == 0) {
// flush raises an exception
em.flush();
em.clear();
}
}
em.getTransaction().commit();
} catch (PersistenceException e) {
logger.debug("I handle unique constraint violation which is completely normal and fine: + e.getMessage()");
// Rollback the transaction and proceed as nothing happened
em.getTransaction().rollback();
} finally {
em.close();
}
Now as some data which has already been in the database comes and is tried to be inserted, an exception is raised, which I would like to handle with the code above.
Instead I get a bunch of exceptions in my log files looking as follows:
17:07:36,495 | WARN | tenerContainer-1 | JDBCExceptionReporter | rnate.util.JDBCExceptionReporter 100 | SQL Error: 1, SQLState: 23000
17:07:36,496 | ERROR | tenerContainer-1 | JDBCExceptionReporter | rnate.util.JDBCExceptionReporter 101 | ORA-00001: unique constraint (MYDB.UNIQUE_MEASUREMENTS) violated
17:07:36,496 | WARN | tenerContainer-1 | JDBCExceptionReporter | rnate.util.JDBCExceptionReporter 100 | SQL Error: 1, SQLState: 23000
17:07:36,497 | ERROR | tenerContainer-1 | JDBCExceptionReporter | rnate.util.JDBCExceptionReporter 101 | ORA-00001: unique constraint (MYDB.UNIQUE_MEASUREMENTS) violated
17:07:36,497 | ERROR | tenerContainer-1 | AbstractFlushingEventListener | ef.AbstractFlushingEventListener 324 | Could not synchronize database state with session
org.hibernate.exception.ConstraintViolationException: could not insert:
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:94)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2285)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2678)
at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:79)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:167)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1028)
at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:304)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:358)
at $Proxy161.flush(Unknown Source)
at MyApp.databaseBinding.DatabaseBindingImpl.saveGeneralMeasurement(DatabaseBindingImpl.java:234)
at MyApp.DatabaseBindingImpl.saveData(DatabaseBindingImpl.java:163)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:307)
at org.springframework.osgi.service.importer.support.internal.aop.ServiceInvoker.doInvoke(ServiceInvoker.java:58)
at org.springframework.osgi.service.importer.support.internal.aop.ServiceInvoker.invoke(ServiceInvoker.java:62)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:131)
at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:119)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.osgi.service.util.internal.aop.ServiceTCCLInterceptor.invokeUnprivileged(ServiceTCCLInterceptor.java:56)
at org.springframework.osgi.service.util.internal.aop.ServiceTCCLInterceptor.invoke(ServiceTCCLInterceptor.java:39)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.osgi.service.importer.support.LocalBundleContextAdvice.invoke(LocalBundleContextAdvice.java:59)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:131)
at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:119)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at $Proxy160.saveData(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.camel.component.bean.MethodInfo.invoke(MethodInfo.java:214)
at org.apache.camel.component.bean.MethodInfo$1.proceed(MethodInfo.java:133)
at org.apache.camel.component.bean.BeanProcessor.process(BeanProcessor.java:137)
at org.apache.camel.impl.ProcessorEndpoint.onExchange(ProcessorEndpoint.java:95)
at org.apache.camel.impl.ProcessorEndpoint$1.process(ProcessorEndpoint.java:65)
at org.apache.camel.processor.SendProcessor$1.doInProducer(SendProcessor.java:97)
at org.apache.camel.processor.SendProcessor$1.doInProducer(SendProcessor.java:95)
at org.apache.camel.impl.ProducerCache.doInProducer(ProducerCache.java:146)
at org.apache.camel.processor.SendProcessor.doProcess(SendProcessor.java:94)
at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:82)
at org.apache.camel.management.InstrumentationProcessor.process(InstrumentationProcessor.java:67)
at org.apache.camel.processor.DelegateProcessor.processNext(DelegateProcessor.java:53)
at org.apache.camel.processor.DelegateProcessor.proceed(DelegateProcessor.java:82)
at org.apache.camel.processor.interceptor.TraceInterceptor.process(TraceInterceptor.java:93)
at org.apache.camel.management.InstrumentationProcessor.process(InstrumentationProcessor.java:67)
at org.apache.camel.processor.RedeliveryErrorHandler.processExchange(RedeliveryErrorHandler.java:177)
at org.apache.camel.processor.RedeliveryErrorHandler.processErrorHandler(RedeliveryErrorHandler.java:143)
at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:88)
at org.apache.camel.processor.DefaultErrorHandler.process(DefaultErrorHandler.java:49)
at org.apache.camel.processor.DefaultChannel.process(DefaultChannel.java:228)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:74)
at org.apache.camel.processor.UnitOfWorkProcessor.processNext(UnitOfWorkProcessor.java:66)
at org.apache.camel.processor.DelegateProcessor.process(DelegateProcessor.java:48)
at org.apache.camel.management.InstrumentationProcessor.process(InstrumentationProcessor.java:67)
at org.apache.camel.component.jms.EndpointMessageListener.onMessage(EndpointMessageListener.java:84)
at org.springframework.jms.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:543)
at org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:482)
at org.springframework.jms.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:451)
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:323)
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:261)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:982)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:974)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:876)
at java.lang.Thread.run(Thread.java:662)
Caused by: java.sql.BatchUpdateException: ORA-00001: unique constraint (MYDB.UNIQUE_MEASUREMENTS) violated
at oracle.jdbc.driver.DatabaseError.throwBatchUpdateException(DatabaseError.java:343)
at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:10720)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
at org.hibernate.jdbc.BatchingBatcher.addToBatch(BatchingBatcher.java:56)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2265)
... 76 more
17:07:36,507 | DEBUG | tenerContainer-1 | DatabaseBindingImpl | abaseBinding.DatabaseBindingImpl 250 | I handle unique constraint violation which is completely normal and fine: javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not insert:
As you can see, my exception handling is only at the end. Apparently there are other components: "JDBCExceptionReporter" and "AbstractFlushingEventListener", who also take care of notifying these exceptions.
As I described before, constraint violation of this kind is an expected thing in this application, and I don't consider it to be an error, and that's why I am handling it in the application code.
Instead of all those stacktraces in the logs I would only like to put there my message saying something like: "One bastard tried to put data already being in the database, too bad...".
How do I get rid of those ERROR messages from the logs? What is the policy of "JDBCExceptionReporter" and "AbstractFlushingEventListener" elements? How to correctly handle JPA exceptions?
I will welcome any opinions and suggestions. Best regards!