2012-04-16 42 views
3

有時即時得到問題的鎖定,如鎖定:問題與交易與Hibernate 4.0

java.sql.SQLTransactionRollbackException: A lock could not be obtained within the time requested 

我使用的是c3p0池休眠,並設置爲樂觀鎖定休眠。

我也有一些代碼繞過Hibernate,並通過獨立配置的c3p0池與數據庫交談。這純粹是因爲這個代碼在我轉移到Hibernate之前就已經存在,並且工作得很好,所以我沒有必要在當時改變它。

現在我想知道是否有兩個獨立配置的c3p0池可能會導致問題。如果不是,我如何才能追蹤這些異常的原因,我將池設置爲20到100個連接,並且我最多隻有12個線程併發,並且我認爲當我完成所有事務/會話時,它們都將被關閉。

編輯:現在有一個游泳池,但仍然得到一個問題,流汗以下錯誤,但沒有詳細說明,以它的原因,有一件事艾韋注意到的是,它總是說託管線程:3

Exception with lookup 
12:42:36,627 WARN ThreadPoolAsynchronousRunner:608 - com[email protected]1ff96a2 -- APPARENT DEADLOCK!!! Creating emergency threads for unassigned pending tasks! 
12:42:36,628 WARN ThreadPoolAsynchronousRunner:624 - com[email protected]1ff96a2 -- APPARENT DEADLOCK!!! Complete Status: 
    Managed Threads: 3 
    Active Threads: 3 
    Active Tasks: 
     co[email protected]fdfb9a (com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#0) 
     co[email protected]914847 (com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2) 
     co[email protected]205390 (com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#1) 
    Pending Tasks: 
     co[email protected]4e171b 
     com.mchange.[email protected]ceeecb 
     com.mchange.[email protected]19f7cec 
     com.mchange.[email protected]1c299f9 
     [email protected]0ab38a 
     [email protected]916a2f 
     com.mchange.[email protected]1d23fbf 
     com.mchange.v2.[email protected] 
     com.mchange.[email protected]1027733 
     com.mchange.[email protected]dfd9b0 
     [email protected]cecbb 
     co[email protected]4a0d0b 
     com.mchange.[email protected]19e809d 
     [email protected]0de0f8 
     [email protected]ce568 
Pool thread stack traces: 
    Thread[com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#0,5,JAIKOZ Thread Group] 
     org.apache.derby.impl.jdbc.EmbedStatement.close(Unknown Source) 
     com.mchange.v1.db.sql.StatementUtils.attemptClose(StatementUtils.java:41) 
     com.mchange.v2.c3p0.stmt.GooGooStatementCache$1StatementCloseTask.run(GooGooStatementCache.java:404) 
     com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:547) 
    Thread[com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2,5,JAIKOZ Thread Group] 
     org.apache.derby.impl.jdbc.EmbedStatement.close(Unknown Source) 
     com.mchange.v1.db.sql.StatementUtils.attemptClose(StatementUtils.java:41) 
     com.mchange.v2.c3p0.stmt.GooGooStatementCache$1StatementCloseTask.run(GooGooStatementCache.java:404) 
     com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:547) 
    Thread[com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#1,5,JAIKOZ Thread Group] 
     org.apache.derby.impl.jdbc.EmbedStatement.close(Unknown Source) 
     com.mchange.v1.db.sql.StatementUtils.attemptClose(StatementUtils.java:41) 
     com.mchange.v2.c3p0.stmt.GooGooStatementCache$1StatementCloseTask.run(GooGooStatementCache.java:404) 
     com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:547) 

這可能是此問題

https://forum.hibernate.org/viewtopic.php?p=2390809

+0

如果更好的話,我可以移動到h2 – 2012-04-18 14:58:15

+0

H2支持多版本併發。它應該有助於避免使用下面的示例中的互斥鎖和鎖。這可能不會傷害嘗試。 – 2012-04-18 15:13:23

回答

0

鑑於SQLTransactionRollbackException是一個數據庫級鎖定失敗,僅在獨立配置C3P0池不是原因這個問題。如果是這樣的話,你將無法運行同一個基於Hibernate的應用程序的兩個實例。

這裏的第一步應該是使用調試器在引發異常時停止。然後檢查其他數據庫連接池線程,看看它們是否正在對數據庫做任何事情。如果它們是,那將是第一個看的地方,因爲你可能會因數據庫級鎖造成死鎖。如果您可以在仍然重現問題的同時關閉池中的線程數,則此步驟可能更容易。

雖然原因可能是由另一個線程獲得的數據庫鎖,然後未被釋放。如果是這樣的話,你必須使用你的數據庫工具來找出異常拋出線程無法獲得的資源,然後嘗試找出誰擁有該鎖以及爲什麼。

祝你好運。

+0

好吧,我確實改變了代碼,問題似乎消失了,但爲了做到這一點,我不得不改變一些其他的東西,所以它可能是對的,這是一個巧合。我感到困惑的一件事是,Hibernate會話打開的時間越長,它就會越長地鎖住數據庫鎖,以前我不認爲它會這樣,但我現在不太確定。 – 2012-04-18 10:28:15

+0

如果你做的事情會得到一個鎖,並且永遠不會告訴Session你完成了,那麼是的,這些鎖仍然會被保留。換一種說法,我肯定會期望Session中打開的任何db鎖在.close()中關閉,如果在事務中關閉,則在.commit()中關閉。如果您從未調用過這些方法,則會根據數據庫設置保留一段時間。 – sharakan 2012-04-18 11:25:10

+0

我總是關閉,並承諾,但如果會話打開了一段時間,真的沒有幫助,我不知道如何找出何時Hibernate實際上獲取鎖 – 2012-04-18 11:45:20

0

我在嵌入式環境中遇到了Hibernate的問題。我們使用SQLite來執行客戶端數據庫操作。我發現嵌入式數據庫具有處理多線程操作的有限或粗糙的方法。 YOu在提交或可能啓動任何事務之前可能必須檢查數據庫上的鎖定。

在SQLite中,當事務正在進行時,您可以將線程輸入讀取。但是,您不能讓一個或多個線程同時寫入或打開事務。另外,很難找到真正的粘貼者,當發生任何查詢時,您不能提交事務!否則,您將遇到類似於您所遇到的鎖定異常。

其實我創建了一個信號量鎖鎖來跟蹤所有打開的讀操作,並能夠安全互動與交易:

/** 
    * Enter read section. Increment the latch so commiting 
    * threads know how many reads are left till it's appropriate 
    * to write/commit. 
    * 
    * @throws InterruptedException the interrupted exception 
    */ 
    public void enterReadSection() throws InterruptedException { 
     if (enableReadLock && (transactionLock.availablePermits()==0)) { 
      readLock.lock(); 
      try { 
       log.debug("Waiting on database unlock."); 
       readWait.await(); 
      } finally { 
       readLock.unlock(); 
       log.debug("Database Unlocked."); 
      } 
     } 

     if (enableReadLock) { 
      synchronized(this) { 
       latch = new CountDownLatch((int)latch.getCount()+1); 
      } 
     } 
    } 

    /** 
    * Exit read section. 
    */ 
    public void exitReadSection() { 
     if (enableReadLock) 
      latch.countDown(); 
    } 

    /** 
    * Trx lock. 
    * 
    * @throws InterruptedException the interrupted exception 
    */ 
    public void trxLock() throws InterruptedException { 
     if (enableTrxLock) 
      transactionLock.acquire(); 
    } 

    /** 
    * Trx unlock. 
    */ 
    public void trxUnlock() { 
     if (enableTrxLock) 
      transactionLock.release(); 
    } 

    /** 
    * Commit lock. 
    * 
    * @throws InterruptedException the interrupted exception 
    */ 
    public void commitLock() throws InterruptedException { 
     if (enableCommitLock) { 
      commitLock.acquire(); 

      //Wait for reading threads to complete 
      latch.await(); 
     } 
    } 

    /** 
    * Commit unlock. 
    * 
    * @throws InterruptedException the interrupted exception 
    */ 
    public void commitUnlock() throws InterruptedException { 
     if(enableCommitLock) { 
      commitLock.release(); 
      releaseRead(); 
     } 
    } 

我知道,一些深層次的魔法對那裏發生的,但它是什麼我趕上了經過多次追蹤和錯誤。我希望它可以更簡單,但通常客戶端/服務器前端數據庫卸載了大部分併發問題,因此您不會像Oracle,mysql,postgres等那樣多次見證它...

我想象你在使用德比時需要某種併發檢查機制,信號或閂鎖。我不太瞭解德比,但它聽起來像它內置了原始的線程安全機制。你可能需要解決這些限制。祝你好運!