2013-02-18 93 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(); 
}