0 Replies Latest reply on Nov 11, 2010 1:33 PM by pimek123

    Handling JPA Exception (unique constraint violation)

    pimek123

      Hello 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!