【问题标题】:hibernate Lock wait timeout exceeded;超过休眠锁等待超时;
【发布时间】:2010-12-29 17:47:33
【问题描述】:

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

【问题讨论】:

    标签: java hibernate transactions


    【解决方案1】:

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

    1. Transaction1 使用您的实体启动、更新(并锁定)行。
    2. Transaction2 尝试执行相同的操作,但由于行仍处于锁定状态而无法执行。所以它会等待(并等待,再等待),直到超过超时时间

    现实生活模拟将有第一个和第二个实体管理器以及在不同线程中的适当更新/事务。这样你就有了:

    1. Transaction1 使用您的实体启动、更新(并锁定)行。
    2. Transaction2 尝试执行相同的操作,但由于行仍处于锁定状态而无法执行。所以它等待(等待,等待)......
    3. 同时提交 Transaction1 并释放锁
    4. 现在可以继续事务 2

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

    更新(基于评论):

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

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

    【讨论】:

    • 我实际上正在尝试编写一个测试用例来查看乐观锁定是否有效,有问题的对象 UserAccount 正在使用版本,请参阅此问题以获取详细信息stackoverflow.com/questions/1938671/concurrency-in-hibernate,在这种情况下有两个线程会transaction2 得到一个 staledObjectException 来检测底层数据的变化?
    • 我已经更新了上面的答案 - 使用两个线程并不是测试特别是乐观锁定的好方法(由于不可预测)
    • 在你的step2中,你的意思是获取em2而不是获取em1?
    • 我认为在 em1.flush 之后移动 em1.commit 就足够了。
    • 是的,对不起。所有 3 个步骤都应该有 3 个不同的实体管理器。
    猜你喜欢
    • 2016-12-16
    • 2011-01-07
    • 1970-01-01
    • 2014-04-04
    • 2019-11-20
    • 2017-02-01
    • 2011-12-25
    • 2018-03-29
    • 1970-01-01
    相关资源
    最近更新 更多