Blanca Hdez
Blanca Hdez

Reputation: 3563

Transaction, hsql, hibernate. No insert ---> Could not synchronize database state with session

i'm trying to run some test cases, but when I try to store one object in the ddbb, there is no insert at all.

First, the test is declared with a @Transactional. So all the queries and operations to the ddbb will be in the same transaction. The part of the code where I get errors is:

public Concept storeConcept(Concept concept) throws DataAccessLayerException {

        if(concept!=null && concept.getUri()!=null){
            super.saveOrUpdate(concept);
            concept = this.findByID(concept.getUri());
            return concept;
        }

        return null;
    }

At this point, I can not see any kind of insert in the log of my ddbb (using hsql).

super: the class where this method is extends AbstractHibernateDAOSupport

The problem comes when I try to find the object stored:

ServiceExecutionException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; nested exception is org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
    at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:191)
    at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:692)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:625)
    at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:191)
    at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:692)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    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:172)
    at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:625)
    at com.playence.platform.services.localImpl.AnnotationsServiceImpl$$EnhancerByCGLIB$$d2c706a9.createAnnotation(<generated>)
    at com.playence.app.mediamanagementTest.TestMediaObjectService.testGetAnnotations(TestMediaObjectService.java:115)
    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.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; nested exception is org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
    at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:675)
    at org.springframework.orm.hibernate3.HibernateAccessor.convertHibernateAccessException(HibernateAccessor.java:412)
    at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:411)
    at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:339)
    at com.app.platform.dao.ConceptDao.findByID(ConceptDao.java:110)
    at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:191)
    at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:692)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:625)
    ... 48 more

Because it is not stored. But when I debug this method, even I'm getting the same error, but the process can continue and the method is able to return the object stored. Maybe that concept is somewhere in another session or in hibernate memory, but I can not really understand this problem.

Thanks in advance

EDIT transaction config

<bean id="transactionManager"
       class="org.springframework.orm.hibernate3.HibernateTransactionManager">
       <property name="sessionFactory" ref="sessionFactory" />
   </bean>

   <aop:aspectj-autoproxy proxy-target-class="true"/><!-- Se puede poner tb a nivel de bean -->

   <tx:advice id="txAdvice" transaction-manager="transactionManager">
       <tx:attributes>
           <tx:method name="*" propagation="REQUIRED" />
       </tx:attributes>
   </tx:advice>
<aop:config>
        <aop:pointcut id="serviceOperation"
            expression="execution(* com.app.daoTests.**.*(..)) "  />
        <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation" />
    </aop:config>

EDIT
I have aswell this error:

9898 [main] ERROR org.hibernate.event.def.AbstractFlushingEventListener - Could not synchronize database state with session

It's very common error, and I have been reading something in other threads, but still can not find solution

Upvotes: 0

Views: 4105

Answers (3)

Blanca Hdez
Blanca Hdez

Reputation: 3563

After a while, I came back to this problem. I have realized, that the problem was not related with the store method itself. In my test method I had something like:

@Test
public void testCreateAnnotation() throws Exception {

  //Store the mediaObject related with the annotations to be created
    mediObjectService.storeMediaObject(MockGenericMediaObjectDataPool.GENERIC_MEDIA_OBJECT1);
    Assert.assertNotNull(geMO.getId());

    //Store annotation
    geAnno.setRelatedMediaObjectId(geMO.getId());
    geAnno.setMediaObjectInternalURI(geMO.getInternalURI());
    annotationService.createAnnotation(MockGenericAnnotationDataPool.TEST_ANNOTATION1);

}

These were two different calls to two different DAO, two different store services to two different tables. As you can see, in the same method. Here is the problem, these two calls must be in two different @Test methods.

    @Test
    public void testCreateAnnotation() throws Exception {

      //Store the mediaObject related with the annotations to be created
        mediObjectService.storeMediaObject(MockGenericMediaObjectDataPool.GENERIC_MEDIA_OBJECT1);

//        annotationService.createAnnotation(MockGenericAnnotationDataPool.TEST_ANNOTATION1);

    }

@Test
    public void testUpdateAnnotation() throws Exception {
        Assert.assertNotNull(annotationService);

        //Store the mediaObject related with the annotations to be created
//      mediObjectService.storeMediaObject(MockGenericMediaObjectDataPool.GENERIC_MEDIA_OBJECT1);


        GenericAnnotation geOriginalAnnotation = annotationService.createAnnotation(MockGenericAnnotationDataPool.TEST_ANNOTATION1);
    annotationService.updateAnnotation(geOriginalAnnotation);

    }

If somebody could explain me the reason of this behavior, I would be really grateful!!
Thanks for all your responses

Upvotes: 0

gkamal
gkamal

Reputation: 21000

saveOrUpdate will not insert records if the id has been set, which is what I think is happening in your case. Hibernate decides between an insert or an update based on the value of the id field - if it is not set and ids are being auto generated it will perform an insert otherwise it will update.

In your case it looks like uri is the id - auto generation is turned off. The Concept object that you are saving is new - no row exists in the DB. saveOrUpdate is trying to update a row and failing.

You should use the merge method instead.

The following info from hibernate documentation should help in understanding the difference.

saveOrUpdate() does the following:

  • if the object is already persistent in this session, do nothing
  • if another object associated with the session has the same identifier, throw an exception
  • if the object has no identifier property, save() it
  • if the object's identifier has the value assigned to a newly instantiated object, save() it
  • if the object is versioned by a or , and the version property value is the same value assigned to a newly instantiated object, save() it otherwise update() the object

and merge() is very different:

  • if there is a persistent instance with the same identifier currently associated with the session, copy the state of the given object onto the persistent instance
  • if there is no persistent instance currently associated with the session, try to load it from the database, or create a new persistent instance the persistent instance is returned the given instance does not become associated with the session, it remains detached

Upvotes: 1

Shivan Dragon
Shivan Dragon

Reputation: 15219

Could be because your bean has the id declared as being auto-generated (auto-incremented) and you're passing a new bean instance to the saveOrUpdate method where you've actually set that id manually. This will make Hibernate think that infact you're not passing a new bean, but that you're trying to update the existing one (because he sees a value present for an auto-generated id). So instead of inserting it, he tries to update it (where id=whatever) and it fails to find it in the database.

Try to either:

  • declare the id as autogenerated/autoincremented AND make sure you don't manually set it when you pass a new instance of your bean to the saveOrUpdate method

  • declare the id as non-autogenerated (i.e. don't specify any auto-generation config for it) AND set it manually when saving a new bean.

  • try using save(...) and merge(...) methods rather then saveOrUpdate(...)

Upvotes: 0

Related Questions