首页 文章

Hibernate资源池关闭太快了

提问于
浏览
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:尝试使用已关闭或已损坏的资源池

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

我很难过可能导致这种情况的原因

1 回答

  • 2

    你有竞争条件;这就是造成关闭连接池错误的原因 .

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

    如果为日志 Logger org.springframework 打开 DEBUG (或可能 TRACE )日志记录并向 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();
    }
    

相关问题