我有以下代码被另一个应用程序调用(无法更改)以读取数据库。
该方法经常在循环中调用,并在数据库中使用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。 (因为我读过某个地方,在高负载情况下最终可能会被称为延迟……我想可能是这种情况)
但是为什么仍然超出池大小? 在继续之前,如何限制该方法并阻塞该方法,直到再次建立连接?
答案 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;
希望这会对您有所帮助。
谢谢:)