Java ComboPooledDataSource超出池大小,并且不重用

时间:2019-03-14 01:33:51

标签: java datasource limit connection-pooling c3p0

我有以下代码被另一个应用程序调用(无法更改)以读取数据库。
该方法经常在循环中调用,并在数据库中使用DOS。
在DB上,我看到有许多连接打开了……增加到几百个……而DB由于负载而崩溃了。

// Called in a loop
private <T> T execute(String query, PostProcessor<T> postProc, PreProcessor preProcs) throws OperationFailedException {
    try (Connection conn 
            = Objects.requireNonNull(dataSourceRef.get(), "No Connection").getConnection();
         PreparedStatement smt = conn.prepareStatement(query)) {
        preProc.process(smt);
        return postProc.process(smt.executeQuery());
    } catch (SQLException e) {
        throw new OperationFailedException(e.getMessage(), e);
    }
}

日期源在...之前初始化

// class variable
// AtomicReference<PooledDataSource> dataSourceRef = new AtomicReference<PooledDataSource>();

// Init method
ComboPooledDataSource cpds = new ComboPooledDataSource();
cpds.setDriverClass(config.getConnectionDriver());
cpds.setJdbcUrl(config.getConnectionString());
cpds.setUser(config.getConnectionUser());
cpds.setPassword(config.getConnectionPassword());
// cpds.setMaxPoolSize(10);
dataSourceRef.getAndSet(cpds); 

我的问题为什么会发生。
我认为由于没有针对每个查询进行池化,因此应该使用新的连接。 同样,通过设置最大池大小也无法正常工作。

我还尝试了try-catch-finally构造,并在使用后关闭了stm和conn。 (因为我读过某个地方,在高负载情况下最终可能会被称为延迟……我想可能是这种情况)

但是为什么仍然超出池大小? 在继续之前,如何限制该方法并阻塞该方法,直到再次建立连接?

1 个答案:

答案 0 :(得分:0)

在c3p0中进行连接轮询期间,您必须考虑一些选项。这些文件已在以下application.property文件中提供

db.driver: oracle.jdbc.driver.OracleDriver // for Oracle
db.username: YOUR_USER_NAME
db.password: YOUR_USER_PASSWORD
db.url: DATABASE_URL
minPoolSize:5 // number of minimum poolSize
maxPoolSize:100 // number of maximum poolSize
maxIdleTime:5 // In seconds. After that time it will realease the unused connection.
maxStatements:1000
maxStatementsPerConnection:100
maxIdleTimeExcessConnections:10000

这里,maxIdleTime是要点。它定义了多少秒将释放未使用的连接。是秒。

另一个是minPoolSize。它定义了在空闲模式下将保持多少个连接。

另一个是maxPoolSize。它定义了在加载模式下将保持的最大连接数。

现在,如何配置ComboPooledDataSource?这是代码:

@Bean
    public ComboPooledDataSource dataSource(){
        ComboPooledDataSource dataSource = new ComboPooledDataSource();

        try {
            dataSource.setDriverClass(env.getProperty("db.driver"));
            dataSource.setJdbcUrl(env.getProperty("db.url"));
            dataSource.setUser(env.getProperty("db.username"));
            dataSource.setPassword(env.getProperty("db.password"));
            dataSource.setMinPoolSize(Integer.parseInt(env.getProperty("minPoolSize")));
            dataSource.setMaxPoolSize(Integer.parseInt(env.getProperty("maxPoolSize")));
            dataSource.setMaxIdleTime(Integer.parseInt(env.getProperty("maxIdleTime")));
            dataSource.setMaxStatements(Integer.parseInt(env.getProperty("maxStatements")));
            dataSource.setMaxStatementsPerConnection(Integer.parseInt(env.getProperty("maxStatementsPerConnection")));
            dataSource.setMaxIdleTimeExcessConnections(10000);

        } catch (PropertyVetoException e) {
            e.printStackTrace();
        }
        return dataSource;
    }

有关详细实现,请检查this thread。在这里,我添加了实际的实现方式

编辑(获得连接)

您可以使用以下方式获得连接:

Session session = entityManager.unwrap(Session.class);
session.doWork(connection -> doSomeStuffWith(connection));

如何获取EntityManager?

@PersistenceContext
private EntityManager entityManager;

希望这会对您有所帮助。

谢谢:)