2015-10-08 67 views
1

我們正在運行最新版本的Hibernate 4和MySQL。我們所有的Hibernate實體都有一個版本字段,註釋爲@版本,因爲我們在整個開發板上使用了樂觀鎖定。我們在應用程序中沒有使用Pessimistic Locking。我的理解是,使用悲觀鎖定時可能會出現LockTimeoutExceptions,但是,即使我們不使用此鎖定策略,我們也經常這樣做。使用樂觀鎖定時發生Hibernate/MySQL LockTimeoutException

在這種特殊場景中,我們有一個執行程序服務,其大小爲1的線程池。當用戶執行某些操作時,我們會爲其他用戶創建通知。我們將此通知創建委託給執行者服務。這些通知可能需要一些時間才能創建,所以我們這樣做,因此用戶不必坐下來等待通知創建完成。我們使用一個單一大小的線程池,以便我們沒有多次處理通知等等。我們想要的是讓這些操作順序排列並運行。每個線程啓動單個事務,創建所有必要的通知,並提交所述事務並關閉實體管理器。

我們得到的異常的堆棧跟蹤如下。任何想法爲什麼我們會在如上所述的場景中鎖定?我不明白。

Lock wait timeout exceeded; try restarting transaction 
    2015-10-08 01:27:52,195 ERROR [NotificationPublishingRunnable] : could not execute statement 
    javax.persistence.LockTimeoutException: could not execute statement 
     at org.hibernate.jpa.spi.AbstractEntityManagerImpl.wrapLockException(AbstractEntityManagerImpl.java:1812) 
     at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1715) 
     at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1677) 
     at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1683) 
     at org.hibernate.jpa.spi.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:1206) 
     at za.co.bsg.ems.server.DB.merge(171bcc9:315) 
     at za.co.bsg.ems.server.repositories.AbstractRepository.merge(171bcc9 ---------------:158) 
     at za.co.bsg.ems.server.services.notification.EmployeeNotificationCRUDServiceSupport.createEmployeeNotification(171bcc9 remotes/origin/11_9 ---------------:97) 
     at za.co.bsg.ems.server.services.notification.EmployeeNotificationCRUDServiceSupport.createEmployeeNotifications(171bcc9 remotes/origin/11_9 ---------------:75) 
     at za.co.bsg.ems.server.services.notification.EmployeeNotificationCreatorSupport.createEmployeeNotifications(171bcc9 remotes/origin/11_9 -----------:80) 
     at za.co.bsg.ems.server.notification.handler.NotificationHandlerManagerSupport.createNotificationsFromRequest(171bcc9 remotes/origin/11_9 ----------:233) 
     at za.co.bsg.ems.server.runnable.notification.NotificationPublishingRunnable.run(171bcc9 remotes/origin/11_9 -------:64) 
     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) 
     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) 
     at java.lang.Thread.run(Thread.java:745) 
    Caused by: org.hibernate.exception.LockTimeoutException: could not execute statement 
     at org.hibernate.dialect.MySQLDialect$1.convert(MySQLDialect.java:447) 
     at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:49) 
     at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:126) 
     at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:112) 
     at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:211) 
     at org.hibernate.id.IdentityGenerator$GetGeneratedKeysDelegate.executeAndExtract(IdentityGenerator.java:96) 
     at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:58) 
     at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3032) 
     at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3558) 
     at org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:98) 
     at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:492) 
     at org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:197) 
     at org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:181) 
     at org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:216) 
     at org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:324) 
     at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:288) 
     at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:194) 
     at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:125) 
     at org.hibernate.jpa.event.internal.core.JpaMergeEventListener.saveWithGeneratedId(JpaMergeEventListener.java:73) 
     at org.hibernate.event.internal.DefaultMergeEventListener.saveTransientEntity(DefaultMergeEventListener.java:271) 
     at org.hibernate.event.internal.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:251) 
     at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:189) 
     at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:85) 
     at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:876) 
     at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:858) 
     at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:863) 
     at org.hibernate.jpa.spi.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:1196) 
     ... 10 more 
    Caused by: java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction 
     at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:996) 
     at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3887) 
     at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3823) 
     at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2435) 
     at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2582) 
     at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2530) 
     at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1907) 
     at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2141) 
     at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2077) 
     at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2062) 
     at org.apache.tomcat.dbcp.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105) 
     at org.apache.tomcat.dbcp.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105) 
     at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:208 
+0

[@ brent777]你有沒有找到解決這個問題的方法?我們有完全相同的問題。 –

+0

@AndrewKew不幸的不是。 – brent777

回答

0

您使用@Version註釋所有實體:這意味着您要使用樂觀鎖定。樂觀鎖定由EntityManger,DAO或Repository進行管理。

在這裏,您正在使用preparedstatement來完成您的數據庫請求。所以你使用的是悲觀鎖定,這是某些數據庫的默認功能。這就是你有LockTimeoutException的原因。

+0

這個答案根本沒有幫助,它主要重複我在我的問題中已經提到的內容。此外,整個應用程序都使用樂觀鎖定,因爲您建議使用「數據庫默認值」,所以它不會退化爲悲觀鎖定。我知道這一點,因爲我們在其他情況下也會爲這個實體接收OptimisticLockExceptions。 – brent777

+1

Brent777我不知道我是否理解你的問題。你說(在你的標題中)你使用樂觀鎖定時有一個LockTimeOutException。我的回答指出,由於您正在使用PreparedStatement,因此您沒有使用樂觀鎖定,而是使用了悲觀鎖定。如果不是你的問題是什麼? – Pracede

+0

我的問題是如何在OptimisticLocking環境中獲得LockTimeoutException。正如我在之前的評論中所說的那樣,我不相信僅僅因爲涉及準備好的陳述而使用悲觀鎖定。那麼爲什麼我會爲同一個實體獲得OptimisticLockExceptions?爲什麼當我的所有查詢都以完全相同的方式編寫並通過實體管理器作爲命名查詢執行時,它有時會比較樂觀,有時甚至是悲觀的?即使我在每個地方都有特定的版本字段,使用悲觀鎖定準備好的語句的參考是什麼? – brent777