2013-07-19 54 views
18

我的應用程序(JAVA的彈簧芯)有多個線程同時運行和訪問數據庫,我在一些peaktime獲得「死鎖發現試圖獲取鎖時,請嘗試重新啓動交易」

07:43:33,400 WARN [org.hibernate.util.JDBCExceptionReporter] SQL Error: 1213, SQLState: 40001 
07:43:33,808 ERROR [org.hibernate.util.JDBCExceptionReporter] Deadlock found when trying to get lock; try restarting transaction 
07:43:33,808 ERROR [org.hibernate.event.def.AbstractFlushingEventListener] Could not synchronize database state with session 
org.hibernate.exception.LockAcquisitionException: could not insert: [com.xminds.bestfriend.frontend.model.Question] 
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:107) 
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66) 
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2436) 
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2856) 
    at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:79) 
    at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:273) 
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:265) 
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:184) 
    at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321) 
    at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51) 
    at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216) 
    at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383) 
    at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133) 
    at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:656) 
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754) 
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723) 
    at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:147) 
    at com.xminds.bestfriend.consumers.Base.onMessage(Base.java:96) 
    at org.springframework.jms.listener.adapter.MessageListenerAdapter.onMessage(MessageListenerAdapter.java:339) 
    at org.springframework.jms.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:535) 
    at org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:495) 
    at org.springframework.jms.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:467) 
    at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:325) 
    at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:263) 
    at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1058) 
    at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1050) 
    at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:947) 
    at java.lang.Thread.run(Thread.java:662) 
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction 
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) 
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) 
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) 
    at java.lang.reflect.Constructor.newInstance(Constructor.java:513) 
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:411) 
    at com.mysql.jdbc.Util.getInstance(Util.java:386) 
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1065) 
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4074) 
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4006) 
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2468) 
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2629) 
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2719) 
    at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2155) 
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2450) 
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2371) 
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2355) 
    at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate(NewProxyPreparedStatement.java:105) 
    at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:46) 
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2416) 
    ... 25 more 

我的代碼變得異常看起來

try 
{ 
     this.consumerTransactionTemplate.execute(new TransactionCallbackWithoutResult(){ 

        @Override 
        protected void doInTransactionWithoutResult(
          TransactionStatus status) 
        { 
         process(); 
        } 

       }); 

    } 
    catch(Exception e){ 
    logger.error("Exception occured " , e); 
     //TODO: Exception handling 
    } 

回答

18

MySQL的InnoDB引擎的運動行級鎖,從而導致即使你的代碼中插入或更新單行(特別是如果有桌子上幾個指標被更新)死鎖。最好的辦法是圍繞此代碼設計代碼,以便在事務由於死鎖而失敗時重試事務。有關MySQL死鎖診斷和可能的解決方法的一些有用信息可用here

在Spring中通過AOP進行死鎖重試的有趣實現可用here。這樣,只需要將註釋添加到要在發生死鎖時重試的方法。

3

埃米爾的回答非常好,它描述了你所得到的問題。不過,我建議你試試spring-retry

這是一個輝煌的框架,通過註釋實現重試模式。

例子:

@Retryable(maxAttempts = 4, backoff = @Backoff(delay = 500)) 
public void doSomethingWithMysql() { 
    consumerTransactionTemplate.execute(
      new TransactionCallbackWithoutResult(){ 
       @Override 
       protected void doInTransactionWithoutResult(     
         TransactionStatus status) 
       { 
        process(); 
       } 

      }); 
} 

如果任何異常,它會當你面對這樣的重試(呼叫)高達4倍的方法doSomethingWithMysql()與500ms的

-1

退避策略錯誤「檢測到死鎖」。您應該檢查您的查詢執行情況,並驗證兩個或多個併發事務是否會導致死鎖。

這些事務應該以相同的順序獲取數據庫鎖,以避免死鎖。

+0

如果問題不在代碼中,但是在試圖同時訪問相同資源的併發系統中,該怎麼辦? –

相關問題