无法进行交易电话

时间:2016-06-09 13:54:28

标签: java sql hibernate junit transactional

在我的代码中,我将数据保存到Microsoft SQL数据库版本10.50.4042.0 我正在使用hibernate-validator版本4.2.0.CR1和hibernate-commons-annotations版本3.2.0.Final

我正在研究由Maven构建的几个连接在Spring框架上的项目。在我的测试项目中(使用junit 4.8.2)我试图通过选择几个xml文件并将它们转换为数据库行来将数据保存到数据库中(一次一行)。在我处理SQL事务的项目中,我使用这个注释将数据发送到数据库

@Transactional(readOnly = false, propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)

我认为问题发生在hibernate的Transactional过程中。但是没有异步调用,XML结构完全有效。我尝试了不同的方法,但问题似乎非常随机地发生,没有任何特定的模式,它无法只保存1个随机数据行。

我得到的错误信息是:

2016-06-09 12:41:01,578: ERROR [http-8080-Processor3] Could not synchronize database state with session
org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
    at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:85)
    at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:70)
    at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:47)
    at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2574)
    at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2478)
    at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2805)
    at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:114)
    at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:268)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:260)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:180)
    at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
    at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
    at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1206)
    at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:375)
    at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:137)
    at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:656)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
    at com.sun.proxy.$Proxy48.save(Unknown Source)

没有其他SQL调用同时更新行。 如果你在hibernate中遇到同样的问题,你能帮忙吗?或者任何其他建议可能会有所帮助。 谢谢

3 个答案:

答案 0 :(得分:2)

实际上这个问题意味着

  1. 无法找到您指定ID的记录。 为了避免这种情况,我总是读取具有相同id的记录,如果我找回记录,那么我会调用update,否则抛出"exception record not found"

  2. 您删除了一个对象,然后尝试更新它。在这种情况下,您需要清除会话session.clear();

  3. 实际答案:

    id属性的Hibernate映射文件中,如果使用任何生成器类,则对于该属性,不应使用setter方法显式设置该值。 如果明确设置Id属性的值,则会导致上述错误。选中此项以避免此错误。

    调查程序:

    但是,为了更好地处理导致问题的原因,请尝试以下方法:

    1. 在您的休眠配置中,set hibernate.show_sql to true。 这应该显示执行的SQL并导致 问题。
    2. 再次设置log levels for Spring and Hibernate to DEBUG 会让你更好地了解哪一行会导致问题。
    3. 创建一个单元测试,无需配置即可复制问题 Spring的一个事务管理器。这应该会给你一个更好的主意 令人讨厌的代码行。
    4. Solution:

      此异常将出现在hibernate的save和saveOrupdate方法的不同场景中。

      如果Object是瞬态的,需要保存可能会发生此异常 条件。

      1. 在提交对象之前刷新数据可能会导致清除所有待处理的对象。
      2. 如果对象具有自动生成的主键,并且您强制已分配键可能会导致异常。
      3. 如果在将对象提交到数据库之前清理对象可能会导致此异常。
      4. 零或不正确的ID: Hibernate除了null或id(保存时不初始化),每点2表示对象未保存。如果您将ID设置为零或其他内容,Hibernate将尝试更新而不是插入,否则它可能会引发此异常。
      5. 对象不存在:这是最容易确定的:是否以某种方式删除了对象?如果是这样,尝试再次删除它将抛出此异常。

      6. 对象陈旧: Hibernate从会话中缓存对象。如果对象被修改,并且Hibernate不知道它,它将抛出此异常 - 请注意异常的StaleStateException部分。

      7. 所以在将对象提交到数据库后需要flushclearclean,而不是之前。

答案 1 :(得分:1)

据我所知,可能存在以下三个原因之一:

  1. 数据库中表的主键未正确映射到您的代码中。
  2. 正在为数据库中的非后备对象触发更新。您可以通过在调试模式下查看对象的id或在日志中打印id来轻松找到它,并检查当时数据库中是否存在具有该ID的记录。
  3. 隔离级别。我看到你在这里使用READ_COMMITTED作为隔离级别。如果上面的两个没有使异常消失,请尝试将DEFAULT设置为隔离级别。默认情况下,隔离级别由数据库层确定,在您的情况下是Microsoft SQL。
  4. 如果上述三个问题都不能解决您的问题,请分享您的代码。

答案 2 :(得分:1)

在阅读你的解释时,我觉得这也是与你的交易隔离程度相关的问题。

READ_COMMITTED隔离级别指定只能访问未在开放事务中理解的记录,因此我认为在您的情况下,随机发生另一个事务访问您的一个或多个记录批量更新,因此它引发了异常。

我认为一个解决方案是,每次按行提交一个提交,每次都验证行的db状态,或者相反,您可以管理此异常,以避免停止进程或事务。