Pergunta

Eu venho fazendo revisão de código (principalmente usando ferramentas como FindBugs) de um de nossos projetos de estimação e FindBugs marcado seguinte código como errônea (pseudocódigo):

Connection conn = dataSource.getConnection();

try{
    PreparedStatement stmt = conn.prepareStatement();
    //initialize the statement
    stmt.execute();
    ResultSet rs =  stmt.getResultSet();
    //get data
}finally{
    conn.close();
}

O erro foi que este código pode não liberar recursos. Eu descobri que o ResultSet e Demonstração não estavam fechados, então eu fechei-los em finalmente:

finally{
    try{
        rs.close()
    }catch(SqlException se){
        //log it
    }
    try{
        stmt.close();
    }catch(SqlException se){
        //log it
    }
    conn.close();
}

Mas eu encontrei o padrão acima em muitos projetos (de muito poucas empresas), e ninguém estava fechando ResultSets ou declarações.

Você teve problemas com ResultSets e Demonstrações não ser fechado quando a conexão é fechada?

I encontrado apenas este e refere-se ao Oracle tendo problemas com fechando ResultSets ao fechar Connections (usamos o Oracle db, daí minhas correções). java.sql.api diz nada em Connection.Close () javadoc.

Foi útil?

Solução

Um problema com apenas fechar a conexão e não o conjunto de resultados, é que, se o seu código de gerenciamento de conexão está usando o pool de conexão, o connection.close() iria apenas colocar a parte de trás de conexão na piscina. Além disso, alguns de banco de dados tem um recurso cursor no servidor que não serão liberados corretamente a menos que seja explicitamente fechada.

Outras dicas

Eu tive problemas com ResultSets não fechadas em Oracle, mesmo que a conexão foi fechada. O erro que eu tenho era

"ORA-01000: maximum open cursors exceeded"

Assim: Sempre feche o ResultSet

Você deve sempre fechar todos os recursos JDBC explicitamente. Como Aaron e John já disse, fechando uma conexão muitas vezes só devolvê-lo a uma piscina e não todos os drivers JDBC são implementados exatamente da mesma forma.

Aqui é um método utilitário que pode ser usado a partir de um bloco finalmente:

public static void closeEverything(ResultSet rs, Statement stmt,
        Connection con) {
    if (rs != null) {
        try {
            rs.close();
        } catch (SQLException e) {
        }
    }
    if (stmt != null) {
        try {
            stmt.close();
        } catch (SQLException e) {
        }
    }
    if (con != null) {
        try {
            con.close();
        } catch (SQLException e) {
        }
    }
}

A Oracle vai lhe dar erros sobre cursores abertos neste caso.

De acordo com: http: //java.sun .com / JavaSE / 6 / docs / api / java / sql / Statement.html

parece que a reutilização de uma declaração irá fechar todos os conjuntos de resultados abertos e fechar uma declaração irá fechar todos os conjuntos de resultados, mas eu não vejo nada sobre o fechamento de uma conexão irá fechar qualquer um dos recursos que ele criou.

Todos esses detalhes são deixados para o provedor de driver JDBC.

É sempre mais seguro para fechar tudo explicitamente. Nós escrevemos uma classe util que envolve tudo com try {xxx} catch (Throwable {} de modo que você pode apenas chamar Utils.close (rs) e Utils.close (stmt), etc, sem ter que se preocupar com exceções que varredura perto supostamente jogar .

A ponte ODBC pode produzir um vazamento de memória com alguns drivers ODBC.

Se você usar um bom driver JDBC, então você deve não tem quaisquer problemas com o fechamento da conexão. Mas há 2 problemas:

  • Será que você sabe se você tem um bom motorista?
  • Você vai usar outros drivers JDBC no futuro?

que a melhor prática é para fechar tudo.

Eu trabalho em um grande ambiente J2EE web. Temos vários bancos de dados que podem ser conectados a em uma única solicitação. Começamos recebendo impasses lógicos em algumas das nossas aplicações. A questão era que, como segue:

  1. Usuário teria pedido página
  2. Ligações Server para DB 1
  3. Seleciona Server em DB 1
  4. Servidor "fecha" conexão com DB 1
  5. Ligações Server para DB 2
  6. Deadlocked!

Isso ocorreu por 2 motivos, estávamos vivendo muito mais elevado volume de tráfego que o normal e o J2EE Spec por padrão, não realmente próximo a sua conexão até que o segmento termina a execução. Assim, no exemplo passo acima de 4 nunca realmente fechou a conexão, mesmo que eles estavam fechadas corretamente no finalmente.

Para corrigir isso, você você tem que usar referências de recursos no web.xml para suas conexões de banco de dados e você tem que definir o res-compartilhamento-escopo para impartilhável.

Exemplo:

<resource-ref>
    <description>My Database</description>
    <res-ref-name>jdbc/jndi/pathtodatasource</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
    <res-sharing-scope>Unshareable</res-sharing-scope>
</resource-ref>

Eu definitivamente vi problemas com ResultSets não fechadas, eo que ele pode ferir a fechá-los o tempo todo, certo? A insegurança de que necessitam para se lembrar de fazer isso é uma das melhores razões para se deslocar às estruturas que gerem estes detalhes para você. Pode não ser viável em seu ambiente de desenvolvimento, mas eu tive muita sorte usando Spring para gerenciar transações JPA. Os detalhes complicados de conexões de abertura, declarações, conjuntos de resultados e escrita / catch / finally blocos try sobre-complicada (com blocos try / catch no bloco finally! ) para fechá-los novamente apenas desaparece, deixando você realmente obter algum trabalho feito. Eu recomendo a migração para esse tipo de solução.

Em Java, Demonstrações (não Resultsets) correlato para cursores em Oracle. É melhor fechar os recursos que você abrir como um comportamento inesperado pode ocorrer em relação aos recursos da JVM e do sistema.

Além disso, alguns JDBC utilização conjunta de quadros piscina Demonstrações e conexões, por isso não fechá-los pode não marcar os objetos como livre na piscina, e problemas de desempenho causa no quadro.

Em geral, se existe um método close () ou destruir () em um objeto, há uma razão para chamá-lo, e ignorá-la é feito por sua própria conta e risco.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top