Estou recebendo uma exceção ORA-01000 SQL. Portanto, tenho algumas dúvidas relacionadas a isso.
- Os cursores máximos abertos estão exatamente relacionados ao número de conexões JDBC ou também aos objetos de instrução e conjunto de resultados que criamos para uma única conexão? (Estamos usando pool de conexões)
- Existe uma maneira de configurar o número de objetos de instrução / conjunto de resultados no banco de dados (como conexões)?
- É aconselhável usar a instrução de variável de instância / objeto de conjunto de resultados em vez de instrução local de método / objeto de conjunto de resultados em um único ambiente de thread?
A execução de uma instrução preparada em um loop causa esse problema? (Claro, eu poderia ter usado sqlBatch) Observação: pStmt é fechado quando o loop termina.
{ //method try starts String sql = "INSERT into TblName (col1, col2) VALUES(?, ?)"; pStmt = obj.getConnection().prepareStatement(sql); pStmt.setLong(1, subscriberID); for (String language : additionalLangs) { pStmt.setInt(2, Integer.parseInt(language)); pStmt.execute(); } } //method/try ends { //finally starts pStmt.close() } //finally ends
O que acontecerá se conn.createStatement () e conn.prepareStatement (sql) forem chamados várias vezes em um único objeto de conexão?
Edit1: 6. O uso do objeto de instrução de referência Weak / Soft ajudará na prevenção do vazamento?
Edit2: 1. Existe alguma maneira, eu posso encontrar todos os "statement.close ()" s ausentes no meu projeto? Eu entendo que não é um vazamento de memória. Mas eu preciso encontrar uma referência de instrução (onde close () não é executado) elegível para coleta de lixo? Alguma ferramenta disponível? Ou tenho que analisá-lo manualmente?
Por favor me ajude a entender isso.
Solução
Para encontrar o cursor aberto no banco de dados Oracle para o nome de usuário -VELU
Vá para a máquina ORACLE e inicie o sqlplus como sysdba.
[oracle@db01 ~]$ sqlplus / as sysdba
Então corra
SELECT A.VALUE,
S.USERNAME,
S.SID,
S.SERIAL#
FROM V$SESSTAT A,
V$STATNAME B,
V$SESSION S
WHERE A.STATISTIC# = B.STATISTIC#
AND S.SID = A.SID
AND B.NAME = 'opened cursors current'
AND USERNAME = 'VELU';
Se possível, leia minha resposta para entender melhor minha solução
for (String language : additionalLangs) {
SYS.V$OPEN_CURSOR
visualização. Isso fornecerá não apenas o SID, mas também o texto SQL.Respostas:
ORA-01000, o erro máximo de cursores abertos, é um erro extremamente comum no desenvolvimento de banco de dados Oracle. No contexto do Java, isso acontece quando o aplicativo tenta abrir mais ResultSets do que cursores configurados em uma instância de banco de dados.
As causas comuns são:
Erro de configuração
Solução:
Vazamento do cursor
fundo
Esta seção descreve parte da teoria por trás dos cursores e como o JDBC deve ser usado. Se você não precisa saber o plano de fundo, pode pular isso e ir direto para 'Eliminar vazamentos'.
O que é um cursor?
Um cursor é um recurso no banco de dados que mantém o estado de uma consulta, especificamente a posição em que um leitor está em um ResultSet. Cada instrução SELECT tem um cursor, e os procedimentos armazenados PL / SQL podem abrir e usar quantos cursores forem necessários. Você pode descobrir mais sobre cursores no Orafaq .
Uma instância de banco de dados normalmente atende a vários esquemas diferentes , muitos usuários diferentes, cada um com várias sessões . Para fazer isso, ele possui um número fixo de cursores disponíveis para todos os esquemas, usuários e sessões. Quando todos os cursores estão abertos (em uso) e chega uma solicitação que exige um novo cursor, a solicitação falha com um erro ORA-010000.
Encontrar e definir o número de cursores
O número é normalmente configurado pelo DBA na instalação. O número de cursores atualmente em uso, o número máximo e a configuração podem ser acessados nas funções do Administrador no Oracle SQL Developer . No SQL, ele pode ser definido com:
Relacionando JDBC na JVM a cursores no banco de dados
Os objetos JDBC abaixo são fortemente acoplados aos seguintes conceitos de banco de dados:
JDBC é thread-safe: é normal passar os vários objetos JDBC entre threads.
Por exemplo, você pode criar a conexão em um segmento; outro encadeamento pode usar essa conexão para criar um PreparedStatement e um terceiro encadeamento pode processar o conjunto de resultados. A única restrição principal é que você não pode ter mais de um ResultSet aberto em um único PreparedStatement a qualquer momento. Consulte O banco de dados Oracle oferece suporte a várias operações (paralelas) por conexão?
Observe que uma confirmação de banco de dados ocorre em uma conexão e, portanto, todos os DML (INSERT, UPDATE e DELETE) nessa conexão serão confirmados juntos. Portanto, se você deseja oferecer suporte a várias transações ao mesmo tempo, deve ter pelo menos uma conexão para cada transação simultânea.
Fechando objetos JDBC
Um exemplo típico de execução de ResultSet é:
Observe como a cláusula finally ignora qualquer exceção gerada pelo close ():
No Java 7, a Oracle introduziu a interface AutoCloseable que substitui a maior parte do padrão Java 6 por alguns bons açúcares sintáticos.
Segurando objetos JDBC
Os objetos JDBC podem ser mantidos com segurança em variáveis locais, instância de objeto e membros de classe. Geralmente é uma prática melhor:
No entanto, há uma exceção: se você estiver usando EJBs ou um contêiner Servlet / JSP, deverá seguir um modelo de threading rígido:
Eliminando vazamentos
Existem vários processos e ferramentas disponíveis para ajudar a detectar e eliminar vazamentos de JDBC:
Durante o desenvolvimento - detectar bugs no início é de longe a melhor abordagem:
Práticas de desenvolvimento: Boas práticas de desenvolvimento devem reduzir o número de bugs em seu software antes que ele deixe a mesa do desenvolvedor. As práticas específicas incluem:
Análise de código estático: Use uma ferramenta como o excelente Findbugs para realizar uma análise de código estático. Isso pega muitos lugares onde o close () não foi tratado corretamente. Findbugs tem um plug-in para Eclipse, mas também funciona de forma autônoma para eventos pontuais, tem integrações com Jenkins CI e outras ferramentas de construção
Em tempo de execução:
Capacidade de retenção e compromisso
Registrando em tempo de execução.
Você pode adicionar um driver JDBC de depuração ao seu projeto (para depuração - não o implemente). Um exemplo (eu não usei) é log4jdbc . Em seguida, você precisa fazer uma análise simples neste arquivo para ver quais execuções não têm um fechamento correspondente. A contagem de aberturas e fechamentos deve destacar se há um problema potencial
Outros pensamentos
Você pode usar WeakReferences para lidar com o fechamento de conexões?
Referências fracas e suaves são maneiras de permitir que você faça referência a um objeto de uma maneira que permita que a JVM colete o referente a qualquer momento que julgar adequado (assumindo que não haja cadeias de referência fortes para esse objeto).
Se você passar um ReferenceQueue no construtor para a referência suave ou fraca, o objeto é colocado no ReferenceQueue quando o objeto é GC'ed quando ocorre (se ocorrer). Com essa abordagem, você pode interagir com a finalização do objeto e pode fechar ou finalizar o objeto naquele momento.
As referências fantasmas são um pouco mais estranhas; seu propósito é apenas controlar a finalização, mas você nunca pode obter uma referência ao objeto original, então será difícil chamar o método close () nele.
No entanto, raramente é uma boa ideia tentar controlar quando o GC é executado (Weak, Soft e PhantomReferences permitem que você saiba após o fato de que o objeto está enfileirado para GC). Na verdade, se a quantidade de memória na JVM for grande (por exemplo, -Xmx2000m), você pode nunca fazer o GC no objeto e ainda terá o ORA-01000. Se a memória da JVM for pequena em relação aos requisitos do seu programa, você pode descobrir que os objetos ResultSet e PreparedStatement são submetidos ao GC imediatamente após a criação (antes que você possa ler a partir deles), o que provavelmente irá falhar seu programa.
TL; DR: O mecanismo de referência fraca não é uma boa maneira de gerenciar e fechar objetos Statement e ResultSet.
fonte
Estou adicionando mais alguns entendimentos.
Loggin como sysdba.
Em Putty (login Oracle):
No SqlPlus:
Nome do usuário:
sys as sysdba
Defina o valor de session_cached_cursors como 0 para que não feche os cursores.
Selecione o conjunto de valus OPEN_CURSORS existente por conexão no banco de dados
Abaixo está a consulta para localizar a lista de SID / conexões com os valores do cursor aberto.
Use a consulta abaixo para identificar os sql's nos cursores abertos
Agora depure o código e aproveite !!! :)
fonte
Corrija o seu código assim:
Tem certeza de que está realmente fechando suas declarações, conexões e resultados?
Para analisar objetos abertos, você pode implementar um padrão de delegador, que envolve o código em torno de seus objetos de estado, conexão e resultado. Então você verá se um objeto será fechado com sucesso.
Um exemplo para: pStmt = obj. getConnection () .prepareStatement (sql);
fonte
Se o seu aplicativo for um aplicativo Java EE em execução no Oracle WebLogic como servidor de aplicativos, uma possível causa para esse problema é a configuração de tamanho do cache de instrução no WebLogic.
Se a configuração de tamanho do cache de instrução para uma fonte de dados específica for quase igual ou maior que a configuração de contagem máxima de cursores abertos do banco de dados Oracle, todos os cursores abertos podem ser consumidos por instruções SQL em cache mantidas abertas pelo WebLogic, resultando no erro ORA-01000.
Para resolver isso, reduza a configuração de tamanho do cache de instrução para cada fonte de dados WebLogic que aponta para o banco de dados Oracle para ser significativamente menor do que a configuração de contagem máxima de cursor no banco de dados.
No WebLogic 10 Admin Console, a configuração de tamanho do cache de instrução para cada fonte de dados pode ser encontrada em Serviços (navegação à esquerda)> Fontes de dados> (fonte de dados individual)> guia Pool de conexão.
fonte
Eu também tinha enfrentado esse problema. A exceção abaixo costumava vir
Eu estava usando Spring Framework com Spring JDBC para camada dao.
Meu aplicativo costumava vazar cursores de alguma forma e, depois de alguns minutos ou mais, costumava me dar essa exceção.
Depois de muita depuração e análise minuciosas, descobri que havia o problema com a indexação, a chave primária e as restrições exclusivas em uma das tabelas que estavam sendo usadas na consulta que estava executando.
Meu aplicativo estava tentando atualizar as colunas que foram indexadas por engano . Portanto, sempre que meu aplicativo estava atingindo a consulta de atualização nas colunas indexadas, o banco de dados estava tentando fazer a reindexação com base nos valores atualizados. Estava vazando os cursores .
Consegui resolver o problema fazendo a indexação adequada nas colunas que foram usadas para pesquisar na consulta e aplicando as restrições apropriadas sempre que necessário.
fonte
Eu enfrentei o mesmo problema (ORA-01000) hoje. Tive um loop for na tentativa {}, para executar uma instrução SELECT em um banco de dados Oracle muitas vezes, (cada vez alterando um parâmetro) e, por fim, {} fiz meu código fechar Resultset, PreparedStatement e Connection como de costume . Mas assim que cheguei a uma quantidade específica de loops (1000), recebi o erro do Oracle sobre muitos cursores abertos.
Com base na postagem de Andrew Alcock acima, fiz alterações para que, dentro do loop, fechasse cada conjunto de resultados e cada instrução depois de obter os dados e antes de fazer o loop novamente, e isso resolveu o problema.
Além disso, o mesmo problema ocorreu em outro loop de Instruções Insert, em outro banco de dados Oracle (ORA-01000), desta vez após 300 instruções. Novamente, foi resolvido da mesma maneira, portanto, PreparedStatement ou ResultSet ou ambos contam como cursores abertos até que sejam fechados.
fonte
Você definiu autocommit = true? Se não, tente isto:
fonte
consulta para encontrar sql que abriu.
fonte
Esse problema ocorre principalmente quando você está usando o pool de conexão, porque quando você fecha a conexão, essa conexão volta para o pool de conexão e todos os cursores associados a essa conexão nunca são fechados, pois a conexão com o banco de dados ainda está aberta. Portanto, uma alternativa é diminuir o tempo de conexão ociosa das conexões no pool, de modo que, sempre que a conexão ficar ociosa por, digamos, 10 segundos, a conexão com o banco de dados será fechada e uma nova conexão criada para colocar no pool.
fonte
Usar o processamento em lote resultará em menos sobrecarga. Veja o seguinte link para exemplos: http://www.tutorialspoint.com/jdbc/jdbc-batch-processing.htm
fonte
Em nosso caso, estávamos usando o Hibernate e tínhamos muitas variáveis referenciando a mesma entidade mapeada do Hibernate. Estávamos criando e salvando essas referências em um loop. Cada referência abria um cursor e o mantinha aberto.
Descobrimos isso usando uma consulta para verificar o número de cursores abertos durante a execução de nosso código, avançando com um depurador e comentando seletivamente as coisas.
Quanto ao motivo de cada nova referência abrir outro cursor - a entidade em questão tinha coleções de outras entidades mapeadas para ela e acho que isso tinha algo a ver com isso (talvez não apenas isso, mas em combinação com a forma como configuramos o modo de busca e Configurações de cache). O próprio Hibernate teve erros relacionados à falha ao fechar os cursores abertos, embora pareça que eles foram corrigidos em versões posteriores.
Como não precisávamos ter tantas referências duplicadas para a mesma entidade de qualquer maneira, a solução foi parar de criar e manter todas essas referências redundantes. Uma vez que fizemos isso, o problema era quando estávamos longe.
fonte
Tive esse problema com minha fonte de dados em WildFly e Tomcat, conectando a um Oracle 10g.
Descobri que, sob certas condições, a instrução não foi fechada, mesmo quando a instrução.close () foi chamada. O problema era com o driver Oracle que estávamos usando: ojdbc7.jar. Este driver é destinado ao Oracle 12c e 11g, e parece que tem alguns problemas quando é usado com o Oracle 10g, então eu fiz downgrade para ojdbc5.jar e agora tudo está funcionando bem.
fonte
Eu enfrentei o mesmo problema porque estava consultando o banco de dados por mais de 1000 iterações. Eu usei try e finalmente no meu código. Mas ainda estava recebendo erro.
Para resolver isso eu apenas loguei no oracle db e executei a consulta abaixo:
ALTER SYSTEM SET open_cursors = 8000 SCOPE = BOTH;
E isso resolveu meu problema imediatamente.
fonte