小编典典

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

hibernate

我正在使用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

阅读 247

收藏
2020-06-20

共1个答案

小编典典

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

  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中加载的实体-测试应在此处失败。
2020-06-20