Java ComboPooledDataSource превышает размер пула и не использует повторно - PullRequest
1 голос
/ 14 марта 2019

У меня есть следующий код, который вызывается другим приложением (которое я не могу изменить) для чтения из базы данных.
Метод вызывается в цикле очень часто и выполняет БД.
ВБД Я вижу, что существует много подключений, которые открываются ... увеличивается до нескольких сотен ... и затем БД рухнул из-за нагрузки.

// 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 голосов
/ 14 марта 2019

Во время опроса соединения в c3p0 вы должны рассмотреть некоторые варианты.Они приведены ниже application.property file:

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;
    }

Для подробностей реализации, пожалуйста, проверьте эту ветку .Здесь я добавил практическую реализацию

Редактировать (Получение соединения)

Вы можете получить соединение, используя следующий способ:

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

Как вы получаете EntityManager?

@PersistenceContext
private EntityManager entityManager;

Надеюсь, это поможет вам.

Спасибо:)

...