2

我正在对我们的数据库执行压力测试,该数据库在 MySQL 上处于休眠状态。我正在使用具有默认配置的 c3p0 连接池,但 maxpoolsize 为 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 个实体,然后我会收到以下三个日志消息之一:

[错误] 14:39:23,127 [Thread-20] SqlExceptionHelper - SQLException 由以下故障引发:com.mchange.v2.resourcepool.ResourcePoolException:尝试使用关闭或损坏的资源池

[信息] 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.mchange.v2.resourcepool.BasicResourcePool@16f7ca - 检出资源的尝试被中断,因为池现在已关闭。[线程:线程 18]

我很困惑可能是什么原因造成的

4

1 回答 1

2

你有一个竞争条件;这就是导致关闭连接池错误的原因。

在您的测试方法中,您正在创建异步使用连接池的新线程,但测试方法本身并不等待它们完成。因此,有可能(我猜很有可能有 100 个线程)其中一些在测试方法完成时还没有完成。在您的测试方法完成后,Spring 正在关闭连接池,因此当一个线程随后尝试使用该池时,它会出错。

如果您打开DEBUG(或可能TRACE)记录器org.springframework的日志记录并向您的addEntity(...)方法添加一个日志语句,您应该会看到它在测试方法完成并且连接池 bean 销毁发生后被调用。

要解决此问题,请使用 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();
}
于 2013-05-02T05:23:00.087 回答