Статьи

Почему вы всегда должны использовать пул соединений с Oracle XE

Вступление

Oracle Express Edition — это бесплатная версия Oracle Enterprise Edition, а ее меньший размер делает ее очень удобной для тестирования различных функций Oracle.

Согласно документации Oracle , Express Edition может использовать не более одного ЦП и 1 ГБ ОЗУ, но в действительности существуют другие ограничения, которые не всегда очевидны.

Аномалия обработки соединения с базой данных

Следующие тесты пытаются смоделировать среду транзакций с низкой задержкой, поэтому соединение арендуется на очень короткий промежуток времени:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
private void simulateLowLatencyTransactions(
        DataSource dataSource, int waitMillis)
        throws SQLException {
    for (int i = 0; i < callCount; i++) {
        try {
            try (Connection connection =
                 dataSource.getConnection()) {
                //Let's assume we are running a
                //short-lived transaction
                sleep(waitMillis);
            }
        } catch (SQLException e) {
            LOGGER.error("Exception on iteration " + i, e);
        }
    }
}

Этот тест работает нормально до тех пор, пока время ожидания не превысит определенного порогового значения, и в этом случае база данных время от времени начинает выдавать следующее исключение:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
ERROR  [main]: c.v.b.h.j.c.OracleConnectionCallTest - Exception on iteration 111
java.sql.SQLException: Listener refused the connection with the following error:
ORA-12516, TNS:listener could not find available handler with matching protocol stack
  
    at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:489) ~[ojdbc6-11.2.0.4.jar:11.2.0.4.0]
    at oracle.jdbc.driver.PhysicalConnection.<init>(PhysicalConnection.java:553) ~[ojdbc6-11.2.0.4.jar:11.2.0.4.0]
    at oracle.jdbc.driver.T4CConnection.<init>(T4CConnection.java:254) ~[ojdbc6-11.2.0.4.jar:11.2.0.4.0]
    at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:32) ~[ojdbc6-11.2.0.4.jar:11.2.0.4.0]
    at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:528) ~[ojdbc6-11.2.0.4.jar:11.2.0.4.0]
    at oracle.jdbc.pool.OracleDataSource.getPhysicalConnection(OracleDataSource.java:280) ~[ojdbc6-11.2.0.4.jar:11.2.0.4.0]
    at oracle.jdbc.pool.OracleDataSource.getConnection(OracleDataSource.java:207) ~[ojdbc6-11.2.0.4.jar:11.2.0.4.0]
    at oracle.jdbc.pool.OracleDataSource.getConnection(OracleDataSource.java:157) ~[ojdbc6-11.2.0.4.jar:11.2.0.4.0]
    at com.vladmihalcea.book.high_performance_java_persistence.jdbc.connection.OracleConnectionCallTest.simulateLowLatencyTransactions(OracleConnectionCallTest.java:50) [test-classes/:na]
    at com.vladmihalcea.book.high_performance_java_persistence.jdbc.connection.OracleConnectionCallTest.testConnections(OracleConnectionCallTest.java:40) [test-classes/:na]

Хотя код однопоточный, Oracle начинает жаловаться на то, что прослушиватель запросов на подключение не может найти обработчик процесса для обслуживания входящего запроса.

Это предположение можно подтвердить, повысив параметры процессов и сеансов до более высокого значения:

1
2
alter system set processes=1000 scope=spfile;
alter system set sessions=1000 scope=spfile;

С этими новыми настройками код работает нормально и исключений не выдается. Хотя увеличение лимитов процессов и сеансов устраняет проблему, это решение является лишь обходным путем и повышает порог подключения, а не устраняет основную причину.

Это возможное объяснение дано в этой заметке IBM по устранению неполадок , в которой говорится, что прослушиватель соединения не может быть немедленно уведомлен событиями закрытия соединения. Это может привести к тому, что прослушиватель соединений неверно установит фактический счетчик соединений и предположит, что максимальное число процессов уже достигнуто.

В Oracle 11g Enterprise Edition эта проблема не воспроизводится.

Исправление

Проницательные читатели заметят проблему, глядя на трассировку стека исключений. OracleDataSource не предлагает какого-либо механизма пула соединений, и это приводит к большим накладным расходам на установление соединения как на драйвере, так и на стороне сервера.

Использование пула соединений устраняет эту проблему, поскольку соединения используются повторно, а не устанавливаются по требованию. Пул соединений значительно сокращает время установления соединения, что также приводит к снижению задержек транзакций и повышению пропускной способности.