2013-02-18 55 views
2

我正在對我們的數據庫執行壓力測試,這是MySQL上的休眠模式。我使用的是默認配置c3p0連接除外的15休眠資源池關閉得太快

interface EntityRepository extends JpaRepository<Entity, UUID> {} 

@Service 
public class EntityService { 

    @Autowired 
    EntityRepository er; 

    @Transactional(propagation = Propagation.REQUIRED) 
    public Entity addEntity(Entity r) { 
     er.save(r); 
    } 
} 

public class StressTest { 

    @Autowired 
    EntityService rs; 

    @Test 
    public void entityStressTest() { 
     for(int i = 0; i < 100; i++) { 
      Thread t = new Thread(new Runnable() { 
       public void run() { 
        rs.addEntity(new Entity()); 
       } 
      } 
      t.start(); 
     } 
    } 
} 

我每次運行這個測試,我創建5-8實體,然後我收到以下三個日誌消息之一maxpoolsize:

[ERROR] 14:39:23127 [線程20] SqlExceptionHelper - 一個SQLEXCEPTION通過以下的故障引起:com.mchange.v2.resourcepool.ResourcePoolException:嘗試使用密閉或破碎資源池

[INFO] 14:48:45,478 [Thread-11] JdbcTransaction - HHH000425:無法關閉會話;吞吐異常[org.hibernate.service.UnknownServiceException:未知服務請求[org.hibernate.stat.spi.StatisticsImplementor]]作爲事務完成

[INFO] 14:49:22,860 [Thread-18] BasicResourcePool - com。 [email protected] - 嘗試檢出資源已中斷,因爲池現在已關閉。 [螺紋:螺紋18]

我難倒,什麼可能會導致這

+0

喜。我不知道是什麼導致了這個問題,但是在某些情況下,當你不願意的時候,在底層資源池上調用close()。你在SEVERE級別的日誌中是否有與c3p0相關的[package com.mchange.v2.resourcepool]輸出?如果由於意外問題導致池內部關閉,則會出現。 (順便說一句,你使用的是什麼版本的c3p0?)否則,你需要追蹤哪些外部事物明確地關閉了池。 – 2013-02-19 01:41:00

+0

如果有幫助,我可以想出一個調試版本,在池關閉時記錄堆棧跟蹤。 (「關閉池」應該是一個非常罕見的事件:連接來來往往,但池通常在其應用程序的完整運行時間內存活。)有關我的電子郵件,請參閱c3p0的文檔,http://www.mchange.com/projects/C3P0 / – 2013-02-19 01:41:25

回答

2

你有一個競爭條件;這就是導致關閉連接池錯誤的原因。

在您的測試方法中,您正在創建異步使用連接池的新線程,但測試方法本身並未等待它們完成。因此,有可能(並且我猜測有100個線程的可能性很高),其中一些在測試方法完成時尚未完成。測試方法完成後,Spring將關閉連接池,因此當線程隨後嘗試使用該池時,它將會出錯。

如果打開DEBUG(或可能TRACE)日誌記錄程序org.springframework,並添加日誌語句將addEntity(...)方法,你應該看到它獲取調用的測試方法完成,連接池豆破壞已經發生之後。

爲了解決這個問題使用的CountDownLatch有主要測試方法等待線程完成後才返回那裏的工作:

@Test 
public void entityStressTest() { 
    int numThreads = 100; 
    final CountDownLatch counter = new CountDownLatch(numThreads); 
    for(int i = 0; i < numThreads; i++) { 
     Thread t = new Thread(new Runnable() { 
      public void run() { 
       rs.addEntity(new Entity()); 
       counter.countDown(); 
      } 
     } 
     t.start(); 
    } 
    counter.await(); 
}