Ao testar o mecanismo de estabelecimento de conexão do Oracle XE, me deparei com o seguinte problema. Embora as conexões sejam fechadas em cada iteração, após 50 a 100 conexões, o Oracle começa a lançar intermitentemente a seguinte exceção:
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.test(OracleConnectionCallTest.java:57) [test-classes/:na]
O teste pode ser encontrado no GitHub :
for (int i = 0; i < callCount; i++) {
try {
long startNanos = System.nanoTime();
try (Connection connection = dataSource.getConnection()) {
}
timer.update(System.nanoTime() - startNanos, TimeUnit.NANOSECONDS);
sleep(waitMillis);
} catch (SQLException e) {
LOGGER.info("Exception on iteration " + i, e);
}
}
Se eu tentar abrir/fechar conexões com um passo de espera de 35 ms, tudo funciona bem. Se eu diminuir a espera para 10 ms a exceção começa a ser lançada de vez em quando.
Um possível motivo pode ser explicado por este artigo: http://www-01.ibm.com/support/docview.wss?uid=swg21603472
Um dos motivos mais comuns para os erros TNS-12516 e/ou TNS-12519 serem relatados é o número máximo configurado de limitação de PROCESSES e/ou SESSIONS sendo atingido. Quando isso ocorre, os manipuladores de serviço para o ouvinte TNS ficam "Bloqueados" e nenhuma nova conexão pode ser feita. Uma vez que o TNS Listener recebe uma atualização do processo PMON associado à instância do banco de dados informando ao TNS Listener que os limites estão abaixo do limite configurado e o banco de dados agora está aceitando retomadas de conectividade de conexões.
- O PMON é responsável por atualizar o listener com informações sobre uma determinada instância, como informações de carga e despachante. A carga máxima para conexões dedicadas é determinada pelo parâmetro PROCESSES. A frequência com que o PMON fornece informações SERVICE_UPDATE varia de acordo com a carga de trabalho da instância. O intervalo máximo entre essas atualizações de serviço é de 10 minutos.
- O ouvinte conta o número de conexões que estabeleceu com a instância, mas não obtém imediatamente informações sobre as conexões que foram encerradas. Somente quando o PMON atualiza o listener via SERVICE_UPDATE o listener é informado da carga atual. Como isso pode levar até 10 minutos, pode haver uma diferença entre o carregamento da instância atual de acordo com o ouvinte e o carregamento real da instância.
Quando o ouvinte acredita que o número atual de conexões atingiu a carga máxima, ele pode definir o estado do manipulador de serviço para uma instância como "bloqueado" e começar a recusar conexões de cliente de entrada com um dos seguintes erros: ora-12519 ou ora-1251 "
Eu queria saber se isso é algum tipo de bug ou é simplesmente como o Oracle foi projetado para funcionar.
Atualizar
No Oracle 11g Enterprise Edition, ele funciona bem, então é uma limitação do XE.
Fixar
Usar o pool de conexões é provavelmente a melhor maneira de corrigir esse problema, o que também reduz o tempo de aquisição da conexão e aumenta os picos de tráfego.
Não é um bug. Esse comportamento é esperado. Se precisar aumentar as conexões, basta alterar o limite de processos:
-- Usando pfile ou spfile, você precisará devolver o db, porque o parâmetro de processos é estático.
E para completar, vale dizer que quando em um ambiente de produção e você precisa aumentar o limite de processos, você também pode precisar aumentar parâmetros correlacionados, como transações e sessões (derivadas de processos). Você pode consultar v$resource_limit para determinar os limites e valores atuais em uso: