hibernate锁定等待超时超时;

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

编辑:我移动em1.getTransaction()。提交在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()上得到以下exception。 为什么?

 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中加载的实体 – 测试应该在这里失败。