簡體   English   中英

hibernate鎖定等待超時超時;

[英]hibernate Lock wait timeout exceeded;

我正在使用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()上得到以下異常。 為什么?

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中加載的實體 - 測試應該在這里失敗。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM