【问题标题】:Trouble making transactional call无法进行事务性调用
【发布时间】:2016-10-10 05:23:49
【问题描述】:

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

我正在处理由基于 Spring 框架构建的 Maven 连接的几个项目。在我的测试项目中(使用 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中遇到同样的问题,您能帮忙吗?或者任何其他建议可能会有所帮助。 谢谢

【问题讨论】:

  • 你检查过相关问题吗? 12 ...如果你发布相关代码,提出建议会更容易。
  • 您的实体有@Version 列吗?您的数据是否被复制(并且您从负载均衡器读取/写入)?

标签: java sql hibernate junit transactional


【解决方案1】:

其实这个问题的意思是

  1. 无法找到您给定 ID 的记录。 为了避免这种情况,如果我找到记录,我总是读取具有相同 ID 的记录,然后我调用更新,否则抛出 "exception record not found"

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

实际答案:

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

调查程序:

但是,要更好地了解导致问题的原因,请尝试以下操作:

  1. 在您的休眠配置中,set hibernate.show_sql to true。 这应该向您显示执行的 SQL 并导致 问题。
  2. 设置log levels for Spring and Hibernate to DEBUG,再次设置这个 会让您更好地了解导致问题的线路。
  3. 创建一个单元测试,在不配置的情况下复制问题 Spring 中的事务管理器。这应该给你一个更好的主意 有问题的代码行。

Solution:

这个异常会出现在hibernate的save和saveOrupdate方法的不同场景中。

如果对象是瞬态的,需要保存可能会出现这个异常 条件。

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

  6. 对象已过时: Hibernate 缓存会话中的对象。如果对象被修改了,而 Hibernate 不知道它,它会抛出这个异常——注意异常的StaleStateException 部分。

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

【讨论】:

    【解决方案2】:

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

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

    如果上述三个都不能解决您的问题,请分享您的代码。

    【讨论】:

      【解决方案3】:

      阅读您的解释,在我看来这也是与您的交易隔离级别有关的问题。

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

      我认为一种解决方案是,按时间对每一行进行一次提交,每次验证该行的数据库状态,或者,您可以通过某种方式管理此异常以避免停止您的进程或事务。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-01
        • 2014-02-17
        • 1970-01-01
        • 1970-01-01
        • 2018-08-13
        • 2019-05-09
        相关资源
        最近更新 更多