Java 超出休眠锁等待超时;
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1956950/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
hibernate Lock wait timeout exceeded;
提问by user217631
I am using Hibernate, trying to simulate 2 concurrent update to the same row in database.
我正在使用 Hibernate,试图模拟对数据库中同一行的 2 个并发更新。
Edit: I moved em1.getTransaction().commit to be right after em1.flush(); I am not getting any StaleObjectException, the two transactions committed successfully.
编辑:我将 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());
I getting the following exception on em2.flush()
. Why?
我在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
采纳答案by ChssPly76
Well, you're trying to get into a deadlock and you're succeeding :-)
好吧,你正试图陷入僵局,但你成功了 :-)
- Transaction1 starts, updates (and locks) row with your entity.
- Transaction2 tries to do the same but can't because the row is still locked. So it waits (and waits, and waits) until timeout is exceeded
- Transaction1 与您的实体一起启动、更新(和锁定)行。
- Transaction2 尝试做同样的事情但不能,因为该行仍然被锁定。所以它等待(等待,等待)直到超时
Real lifesimulation would have 1st and 2nd entity manager plus appropriate updates / transactions in separate threads. That way you'd have:
现实生活中的模拟将具有第一个和第二个实体管理器以及在单独线程中的适当更新/事务。这样你就会有:
- Transaction1 starts, updates (and locks) row with your entity.
- Transaction2 tries to do the same but can't because the row is still locked. So it waits (and waits, and waits) ...
- Meanwhile Transaction1 is committed and lock is released
- Transaction2 can now proceed
- Transaction1 与您的实体一起启动、更新(和锁定)行。
- Transaction2 尝试做同样的事情但不能,因为该行仍然被锁定。所以它等待(等待,等待)......
- 同时提交 Transaction1 并释放锁
- Transaction2 现在可以继续了
Note that at that point (#4 above) you'd be overwriting changes made by Transaction1. Hibernate can use optimistic lockingas well as pessimistic lockingto prevent that from happening.
请注意,此时(上面的#4)您将覆盖 Transaction1 所做的更改。Hibernate 可以使用乐观锁和悲观锁来防止这种情况发生。
Update(based on comment):
更新(基于评论):
If the entity is versioned, Transaction2 (#4 above) will fail. However, your code as posted does not get to that point because Transaction2 can't obtain the lock as explained above. If you want to specifically test that optimistic version control is working you can do the following:
如果实体是版本化的,Transaction2(上面的#4)将会失败。但是,您发布的代码并没有达到这一点,因为 Transaction2 无法获得如上所述的锁。如果您想专门测试乐观版本控制是否正常工作,您可以执行以下操作:
- Obtain em1, start transaction, get your entity, committransaction, closeem1.
- Obtain em2, start transaction, get your entity, update your entity, commit transaction, close em2.
- Obtain em3, start transaction, attempt to update entity you've loaded in step 1 - test should fail here.
- 获取em1,启动事务,获取你的实体,提交事务,关闭em1。
- 获取em2,启动事务,获取你的实体,更新你的实体,提交事务,关闭em2。
- 获取 em3,启动事务,尝试更新您在步骤 1 中加载的实体 - 此处测试应该失败。