Transaction,hsql,hibernate。没有插入--->无法将数据库状态与会话同步

时间:2011-12-09 14:47:54

标签: hibernate transactions hsqldb

我试图运行一些测试用例,但是当我尝试在ddbb中存储一个对象时,根本就没有插入。

首先,使用@Transactional声明测试。因此,ddbb的所有查询和操作都将在同一个事务中。我得到错误的代码部分是:

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;
    }

此时,我在ddbb的日志中看不到任何类型的插入(使用hsql)。

super:此方法为extends AbstractHibernateDAOSupport

的类

当我尝试找到存储的对象时出现问题:

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

因为它没有存储。但是当我调试这个方法时,即使我得到相同的错误,但是该过程可以继续并且该方法能够返回存储的对象。 也许这个概念在另一个会话或休眠内存中,但我无法真正理解这个问题。

提前致谢

编辑交易配置

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

修改
我还有这个错误:

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

这是非常常见的错误,我一直在阅读其他帖子中的内容,但仍无法找到解决方案

3 个答案:

答案 0 :(得分:1)

如果已经设置了id,saveOrUpdate将不会插入记录,这是我认为在你的情况下发生的事情。 Hibernate根据id字段的值决定插入或更新 - 如果没有设置并且ids是自动生成的,它将执行插入,否则它将更新。

在你的情况下,看起来uri是id - 自动生成已关闭。您要保存的Concept对象是新的 - DB中不存在任何行。 saveOrUpdate正在尝试更新行并失败。

您应该使用合并方法。

来自hibernate documentation的以下信息应该有助于理解差异。

saveOrUpdate()执行以下操作:

  • 如果该对象在此会话中已经持久化,则不执行任何操作
  • 如果与会话关联的另一个对象具有相同的标识符,则抛出异常
  • 如果对象没有标识符属性,则保存()它
  • 如果对象的标识符具有分配给新实例化对象的值,则保存()它
  • 如果对象是由or版本化的,并且version属性值是分配给新实例化对象的相同值,则save()它 否则更新()对象

和merge()非常不同:

  • 如果当前存在具有相同标识符的持久性实例 与会话相关联,将给定对象的状态复制到 持久化实例
  • 如果当前没有持久性实例 与会话相关联,尝试从数据库加载它,或 创建一个新的持久化实例,返回持久化实例 它不会与给定实例关联 保持独立

答案 1 :(得分:0)

可能是因为你的bean声明为自动生成的id(自动递增),并且你将 new bean实例传递给saveOrUpdate方法,你实际上已经设置了该id手动。这将使Hibernate认为你实际上并没有传递新的bean,而是你正在尝试更新现有的bean(因为他看到了一个自动生成的id存在的值)。因此,他试图更新它(where id=whatever)而不是插入它,而无法在数据库中找到它。

尝试:

  • 将id声明为autogenerated / autoincremented,并确保在将bean的新实例传递给saveOrUpdate方法时不要手动设置它

  • 将id声明为非自动生成(即不为其指定任何自动生成配置)并在保存新bean时手动设置它。

  • 尝试使用save(...)merge(...)方法,而不是saveOrUpdate(...)

答案 2 :(得分:0)

过了一会儿,我回到了这个问题。我已经意识到,问题与存储方法本身无关。在我的测试方法中,我有类似的东西:

@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);

}

这是对两个不同DAO的两个不同调用,两个不同的存储服务到两个不同的表。如您所见,采用相同的方法。这是问题,这两个调用必须使用两种不同的@Test方法。

    @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);

    }

如果有人能解释我这种行为的原因,我会非常感激!! 感谢您的所有回复