Pregunta

He estado revisando el código (principalmente usando herramientas como FindBugs) de uno de nuestros proyectos favoritos y FindBugs marcó el siguiente código como erróneo (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();
}

El error fue que es posible que este código no libere recursos.Descubrí que ResultSet y Statement no estaban cerrados, así que finalmente los cerré:

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

Pero encontré el patrón anterior en muchos proyectos (de bastantes empresas) y nadie cerraba ResultSets o Statements.

¿Tuvo problemas con los conjuntos de resultados y las declaraciones que no se cerraban cuando se cerraba la conexión?

solo encontré este y se refiere a que Oracle tiene problemas para cerrar ResultSets al cerrar Connections (usamos Oracle db, de ahí mis correcciones).java.sql.api no dice nada en el javadoc Connection.close().

¿Fue útil?

Solución

Un problema al cerrar SÓLO la conexión y no el conjunto de resultados es que si su código de administración de conexión utiliza la agrupación de conexiones, el connection.close() simplemente volvería a poner la conexión en el grupo.Además, algunas bases de datos tienen un recurso de cursor en el servidor que no se liberará correctamente a menos que se cierre explícitamente.

Otros consejos

Tuve problemas con ResultSets no cerrados en Oracle, aunque la conexión estaba cerrada.El error que me salió fue

"ORA-01000: maximum open cursors exceeded"

Entonces:¡Cierra siempre tu ResultSet!

Siempre debes cerrar todos los recursos JDBC explícitamente.Como ya dijeron Aaron y John, cerrar una conexión a menudo solo la devolverá a un grupo y no todos los controladores JDBC se implementan exactamente de la misma manera.

Aquí hay un método de utilidad que se puede usar desde un bloque 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) {
        }
    }
}

En este caso, Oracle le dará errores sobre cursores abiertos.

De acuerdo a: http://java.sun.com/javase/6/docs/api/java/sql/Statement.html

Parece que reutilizar una declaración cerrará cualquier conjunto de resultados abierto, y cerrar una declaración cerrará cualquier conjunto de resultados, pero no veo nada acerca de que cerrar una conexión cerrará cualquiera de los recursos que creó.

Todos esos detalles quedan en manos del proveedor del controlador JDBC.

Siempre es más seguro cerrar todo explícitamente.Escribimos una clase de utilidad que envuelve todo con try{ xxx } catch (Throwable {} para que puedas llamar a Utils.close(rs) y Utils.close(stmt), etc. sin tener que preocuparte por las excepciones que supuestamente arrojan el análisis de cierre. .

El puente ODBC puede producir una pérdida de memoria con algunos controladores ODBC.

Si utiliza un buen controlador JDBC, no debería tener ningún problema para cerrar la conexión.Pero hay 2 problemas:

  • ¿Sabes si tienes un buen conductor?
  • ¿Utilizará otros controladores JDBC en el futuro?

Que la mejor práctica es cerrarlo todo.

Trabajo en un gran entorno web J2EE.Disponemos de varias bases de datos a las que se pueden conectar en una sola solicitud.Comenzamos a tener puntos muertos lógicos en algunas de nuestras aplicaciones.El problema era el siguiente:

  1. El usuario solicitaría la página
  2. El servidor se conecta a DB 1
  3. El servidor selecciona en DB 1
  4. El servidor "cierra" la conexión con DB 1
  5. El servidor se conecta a DB 2
  6. ¡Estancado!

Esto ocurrió por 2 razones: estábamos experimentando un volumen de tráfico mucho mayor de lo normal y la especificación J2EE de forma predeterminada no cierra la conexión hasta que el hilo finaliza la ejecución.Entonces, en el ejemplo anterior, el paso 4 nunca cerró la conexión a pesar de que se cerraron correctamente finalmente.

Para solucionar este problema, debe utilizar referencias de recursos en web.xml para sus conexiones de base de datos y debe configurar res-sharing-scope en no compartir.

Ejemplo:

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

Definitivamente he visto problemas con ResultSets no cerrados, y ¿qué daño puede tener cerrarlos todo el tiempo, verdad?La falta de confiabilidad de tener que recordar hacer esto es una de las mejores razones para pasar a marcos que administren estos detalles por usted.Puede que no sea factible en su entorno de desarrollo, pero he tenido mucha suerte al utilizar Spring para gestionar transacciones JPA.Los detalles complicados de abrir conexiones, declaraciones, conjuntos de resultados y escribir bloques try/catch/finally demasiado complicados (con bloques try/catch en el bloque finalmente!) para cerrarlos nuevamente simplemente desaparece, dejándote realmente trabajar.Recomiendo encarecidamente migrar a ese tipo de solución.

En Java, las declaraciones (no los conjuntos de resultados) se correlacionan con los cursores en Oracle.Es mejor cerrar los recursos que abre, ya que puede ocurrir un comportamiento inesperado con respecto a la JVM y los recursos del sistema.

Además, algunos marcos de agrupación JDBC agrupan declaraciones y conexiones, por lo que no cerrarlas podría no marcar esos objetos como libres en el grupo y causar problemas de rendimiento en el marco.

En general, si hay un método close() o destroy() en un objeto, hay una razón para llamarlo, e ignorarlo se hace bajo su propio riesgo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top