当前位置: 首页 > 面试题库 >

休眠锁定等待超时已超过;

边桐
2023-03-14
问题内容

我正在使用Hibernate,试图模拟2个并发更新到数据库中的同一行。

编辑:我将em1.getTransaction()。commit移到em1.flush()之后;我没有收到任何StaleObjectException,两个事务已成功提交。

Session em1=Manager.sessionFactory.openSession();
Session em2=Manager.sessionFactory.openSession();

em1.getTransaction().begin();
em2.getTransaction().begin();

UserAccount c1 = (UserAccount)em1.get( UserAccount.class, "root" );
UserAccount c2 = (UserAccount)em2.get( UserAccount.class, "root" );

c1.setBalance( c1.getBalance() -1 );
em1.flush();
System.out.println("balance1 is "+c2.getBalance());
c2.setBalance( c2.getBalance() -1 );
em2.flush(); // fail

em1.getTransaction().commit();
em2.getTransaction().commit();

System.out.println("balance2 is "+c2.getBalance());

我在上遇到以下异常em2.flush()。为什么?

2009-12-23 21:48:37,648  WARN JDBCExceptionReporter:100 - SQL Error: 1205, SQLState: 41000
2009-12-23 21:48:37,649 ERROR JDBCExceptionReporter:101 - Lock wait timeout exceeded; try restarting transaction
2009-12-23 21:48:37,650 ERROR AbstractFlushingEventListener:324 - Could not synchronize database state with session
org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch update
    at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:126)
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:114)
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
    at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)
    at org.hibernate.persister.entity.AbstractEntityPersister.processGeneratedProperties(AbstractEntityPersister.java:3702)
    at org.hibernate.persister.entity.AbstractEntityPersister.processUpdateGeneratedProperties(AbstractEntityPersister.java:3691)
    at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:147)
    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:168)
    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 com.ch.whoisserver.test.StressTest.main(StressTest.java:54)
Caused by: java.sql.BatchUpdateException: Lock wait timeout exceeded; try restarting transaction
    at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:1213)
    at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:912)
    at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
    at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
    ... 10 more

问题答案:

好吧,您正试图陷入僵局,并且成功了:-)

  1. Transaction1开始,与您的实体更新(和锁定)行。
  2. Transaction2尝试执行相同操作,但由于行仍处于锁定状态而无法执行。因此它等待(并等待,然后等待)直到超过超时时间

现实生活中的 模拟将具有第一和第二实体管理器,以及在单独线程中进行适当的更新/交易。这样,您将拥有:

  1. Transaction1开始,与您的实体更新(和锁定)行。
  2. Transaction2尝试执行相同操作,但由于行仍处于锁定状态而无法执行。因此它等待(然后等待,然后等待)…
  3. 同时,Transaction1已提交并且锁已释放
  4. 现在可以进行Transaction2

请注意,此时(上面的#4)您将覆盖Transaction1所做的更改。Hibernate可以使用乐观锁定和悲观锁定来防止这种情况的发生。

更新 (基于评论):

如果对实体进行版本控制,则Transaction2(上面的#4)将失败。但是,由于如上所述Transaction2无法获得锁,因此您发布的代码无法达到目的。如果要专门测试开放式版本控制是否正常工作,可以执行以下操作:

  1. 获取em1,启动事务,获取您的实体, 提交 事务, 关闭 em1。
  2. 获取em2,开始事务,获取您的实体,更新您的实体,提交事务,关闭em2。
  3. 获取em3,启动事务,尝试更新您在步骤1中加载的实体-测试应在此处失败。


 类似资料:
  • 问题内容: 更新记录时,我反复出现锁定超时超出异常的情况。 我正在使用Java Struts 2.1 Hibernate配置。使用的数据库是MYSQL。 任何人都知道如何解决它。 问题答案: 这里有一些建议: “ 锁定等待超时 ”通常发生在事务正在等待要更新的数据行上,而该行已被某些其他事务锁定时。 在大多数情况下,问题出在数据库方面。可能的原因可能是表格设计不当,数据量大,约束等。 请查看这个详

  • 这是我的servlet的doPost方法,理论上它在db中添加数据 这里是在db中插入数据的方法 但是,当我尝试使用servlet执行此操作时,出现了以下错误 错误1205(HY000):超出锁定等待超时; 有人知道如何解决?如果我对一个普通的java类做同样的事情,那么一切都很好。

  • 在Bash脚本中,我想做如下操作: 一、 例如,在后台启动两个应用程序,并给他们60秒时间完成工作。然后,如果他们没有在这段时间内完成,就杀了他们。 不幸的是,上面的方法行不通,因为< code>timeout是一个可执行文件,而< code>wait是一个shell命令。我试着把它改成: 但是这仍然不起作用,因为< code>wait只能在同一个shell中启动的PID上调用。 有什么想法吗?

  • 问题内容: 在Bash脚本中,我想执行以下操作: 即,在后台启动两个应用程序,并给它们60秒以完成其工作。然后,如果他们没有在该时间间隔内完成,请杀死他们。 不幸的是,上述内容不起作用,因为它是可执行文件,而它是Shell命令。我尝试将其更改为: 但这仍然行不通,因为只能在同一外壳程序内启动的PID上进行调用。 有任何想法吗? 问题答案: 将PID写入文件并像这样启动应用程序: 这将创建另一个hi

  • 问题内容: 我使用Node.js和TypeScript,并且使用。这是我的测试用例: 我想为整个功能设置一个超时时间。即如果要花费2秒,花费0.5秒,花费5秒,我想在3秒钟后让我抛出错误的超时。 正常调用是一个问题,因为范围丢失了: 而且我不能用普通的方式抓住它: 有关如何解决的任何想法? 问题答案: 您可以使用超时: 您必须将其包装在诺言中才能使用。

  • 问题内容: 我想知道WebDriver等待超时和隐式等待超时之间的技术差异。 问题答案: 如文档中所述: 在内部设置将用于所有连续搜索的超时。如果找不到该元素,它将尝试在指定的时间内反复查找该元素。它仅执行此操作,不能强制执行其他任何操作- 它等待元素显示。 ,或者只是您用于特定搜索的一次计时器。它具有更大的可扩展性,意味着您可以将其设置为等待可能需要的任何条件。通常,您可以使用一些预构建的元素来