Java 超过休眠锁等待超时;

Java 超过休眠锁等待超时;,java,hibernate,transactions,Java,Hibernate,Transactions,我正在使用Hibernate,试图模拟对数据库中同一行的2次并发更新 编辑:我将em1.getTransaction().commit移动到em1.flush()之后;我没有收到任何StaleObjectException,这两个事务已成功提交 Session em1=Manager.sessionFactory.openSession(); Session em2=Manager.sessionFactory.openSession(); em1.getTransaction().begin

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

好吧,你试图陷入僵局,你成功了:-)

  • Transaction1启动、更新(并锁定)实体的行
  • Transaction2尝试执行相同操作,但无法执行,因为该行仍处于锁定状态。所以它一直等待(一直等待,一直等待),直到超过超时
  • 真实生活模拟将在单独的线程中包含第一个和第二个实体管理器以及适当的更新/事务。这样你就可以:

  • Transaction1启动、更新(并锁定)实体的行
  • Transaction2尝试执行相同操作,但无法执行,因为该行仍处于锁定状态。所以它等待(等待,等待)
  • 同时提交Transaction1并释放锁
  • 事务2现在可以继续
  • 请注意,此时(#4)您将覆盖Transaction1所做的更改。Hibernate可以使用,也可以防止这种情况发生

    更新(根据评论):

    如果实体进行了版本控制,事务2(上面的4)将失败。但是,您发布的代码没有达到这一点,因为Transaction2无法获得如上所述的锁。如果要专门测试乐观版本控制是否正常工作,可以执行以下操作:

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

  • 我实际上是在写一个测试用例,看看乐观锁定是否有效,问题中的object UserAccount正在使用版本,请查看这个问题的详细信息,在这种情况下,如果使用两个线程,transaction2会得到staledObjectException来检测基础数据的更改吗?我已经更新了上面的答案-在步骤2中使用两个线程不是测试特定乐观锁定(由于不可预测)的好方法,你的意思是获取em2而不是获取em1吗?我想在em1.flush之后移动em1.commit应该足够了。是的,对不起。所有3个步骤都应该有3个不同的实体经理。