2010-02-08 24 views
83

Me estoy haciendo un poco confundido, estaba leyendo el siguiente de http://en.wikipedia.org/wiki/Java_Database_Connectivityse cierren las conexiones de base de datos en Java

Connection conn = DriverManager.getConnection(
    "jdbc:somejdbcvendor:other data needed by some jdbc vendor", 
    "myLogin", 
    "myPassword"); 

Statement stmt = conn.createStatement(); 
try { 
    stmt.executeUpdate("INSERT INTO MyTable(name) VALUES ('my name') "); 
} finally { 
    //It's important to close the statement when you are done with it 
    stmt.close(); 
} 

¿No debe cerrar la conexión conn? ¿Qué está pasando realmente si el conn.close() no ocurre?

Tengo una aplicación web privada que estoy manteniendo que actualmente no cierra ninguna de las dos formas, pero ¿es la más importante la primera, la que está conectada, o ambas?

El sitio sigue bajando intermitentemente pero el servidor sigue diciendo que es un problema de conexión a la base de datos, mi sospecha es que no se está cerrando, pero no sé cuál cerrar para ninguno.

Respuesta

150

Cuando haya terminado con el uso del Connection, debe cerrar explícitamente llamando a su método close() con el fin de liberar a todos los demás recursos de bases de datos (cursores, mangos, etc.) la conexión se puede aferrarse a.

En realidad, el patrón de seguridad en Java es cerrar su ResultSet, Statement y Connection (en ese orden) en un bloque finally cuando haya terminado con ellos, algo así:

Connection conn = null; 
PreparedStatement ps = null; 
ResultSet rs = null; 

try { 
    // Do stuff 
    ... 

} catch (SQLException ex) { 
    // Exception handling stuff 
    ... 
} finally { 
    if (rs != null) { 
     try { 
      rs.close(); 
     } catch (SQLException e) { /* ignored */} 
    } 
    if (ps != null) { 
     try { 
      ps.close(); 
     } catch (SQLException e) { /* ignored */} 
    } 
    if (conn != null) { 
     try { 
      conn.close(); 
     } catch (SQLException e) { /* ignored */} 
    } 
} 

El finally bloque puede ser mejorado ligeramente en (para evitar el cheque nulo):

} finally { 
    try { rs.close(); } catch (Exception e) { /* ignored */ } 
    try { ps.close(); } catch (Exception e) { /* ignored */ } 
    try { conn.close(); } catch (Exception e) { /* ignored */ } 
} 

Pero, aún así, esto es extremadamente detallado por lo que generalmente terminan usando una clase de ayuda a c perder los objetos en los métodos de ayuda nulos de fallos y el bloque finally se convierte en algo así:

} finally { 
    DbUtils.closeQuietly(rs); 
    DbUtils.closeQuietly(ps); 
    DbUtils.closeQuietly(conn); 
} 

Y, en realidad, la Apache Commons DbUtils tiene una clase DbUtils que está haciendo precisamente lo que no hay necesidad de escribir el suyo propio.

+3

¡Ayuda impresionante, gracias! No capté ni pensé en las declaraciones conn! = Null. – onaclov2000

+1

@ onaclov2000 Sí, 'rs',' ps', 'conn' pueden ser' null', según donde se rompa el código. Es por eso que esto se conoce como el patrón "seguro". –

+10

@Pascal Thivent: En realidad, no es necesario que los cierremos todos. El libro "Core Java Volume two - Advanced Features" ha escrito: El método 'close' de un objeto' Statement' cierra automáticamente el 'ResultSet' asociado si la sentencia tiene un conjunto de resultados abierto. De forma similar, el método 'close' de la clase' Connection' cierra todas las 'Statements' de' Connection'. –

6

Sí, debe cerrar la conexión. De lo contrario, el cliente de la base de datos mantendrá normalmente abierta la conexión de socket y otros recursos.

+0

... hasta que se cierre. Esto vincula varios recursos finitos en el lado del cliente y del servidor. Si un cliente hace demasiado este tipo de cosas, puede causar problemas para el cliente mismo, el servicio de base de datos y posiblemente incluso para otras aplicaciones que se ejecutan en el equipo del cliente o del servidor. –

8

Sí. Debe cerrar el conjunto de resultados, la declaración y la conexión. Si la conexión proviene de un grupo, cerrarla realmente la envía al grupo para su reutilización.

Por lo general, tiene que hacer esto en un bloque finally{}, de modo que si se produce una excepción, todavía tiene la posibilidad de cerrar esto.

Muchos marcos se ocuparán de este problema de asignación/desasignación de recursos por usted. p.ej. Spring's JdbcTemplate. Apache DbUtils tiene métodos para controlar el resultado/declaración/conexión, ya sea nulo o no (y detectar excepciones al cerrar), lo que también puede ser útil.

+0

Cuando inserto un eclipse "finalmente" le gusta resaltarlo diciéndome que está mal. ¿debería ir después de los bloques de captura? – onaclov2000

+2

Mierda, acabo de responder mi propia pregunta y lo intenté, lo siento – onaclov2000

+0

Sí. try {} catch {} finally {}. La captura {} es opcional, por cierto. Al igual que finalmente {} –

9

Basta con cerrar Statement y Connection. No es necesario cerrar explícitamente el objeto ResultSet.

documentación

Java dice acerca java.sql.ResultSet:

Un objeto ResultSet se cierra automáticamente por el objeto Statement que lo generó cuando ese objeto Statement se cierra, vuelve a ejecutar, o se utiliza para recuperar el siguiente resultado de una secuencia de resultados múltiples.


BalusC Gracias por los comentarios: "Yo no depender de que algunos controladores JDBC fallan en eso.".

+14

No confiaría en eso. Algunos controladores JDBC fallan en eso. P.ej. Oracle con "Máximo de cursores abiertos excedidos", etc. Simplemente cierre explícitamente todos los recursos abiertos, sin excusas. – BalusC

41

Siempre es mejor cerrar los objetos de base de datos/recursos después del uso. Es mejor cerrar los objetos de conexión, conjunto de resultados y declaración en el bloque finally.

Hasta Java7, todos estos recursos deben cerrarse usando un bloque finally. Si está utilizando Java 7, entonces, para cerrar los recursos, puede hacer lo siguiente.

try(Connection con = getConnection(url, username, password, "org.postgresql.Driver"); 
    Statement stmt = con.createStatement(); 
    ResultSet rs = stmt.executeQuery(sql); 
) { 

//statements 
}catch(....){} 

Ahora, estafa, STMT y RS objetos se convierten en parte del bloque try y Java se cierra automáticamente estos recursos después de su uso.

Espero que haya sido útil.

+0

¿Qué sucede si mi extracto es implícito, es decir, '' ResultSet rs = conn.createStatement(). ExecuteQuery (sql); '' dentro del bloque '' try''? – Antares42

+1

No podrás hacer referencia a ellos en el bloque {} final para el cierre. Si se lanza una excepción, nunca se invocará el método close() del ResultSet – Dan

0

En realidad, es mejor si usa un bloque try-with-resources y Java cerrará todas las conexiones cuando salga del bloque try.

Debe hacer esto con cualquier objeto que implemente AutoClosable.

try (Connection connection = getDatabaseConnection(); Statement statement = connection.createStatement()) { 
    String sqlToExecute = "SELECT * FROM persons"; 
    try (ResultSet resultSet = statement.execute(sqlToExecute)) { 
     if (resultSet.next()) { 
      System.out.println(resultSet.getString("name"); 
     } 
    } 
} catch (SQLException e) { 
    System.out.println("Failed to select persons."); 
} 

La llamada a getDatabaseConnection está acabada. Reemplácelo con una llamada que le proporcione una conexión JDBC SQL o una conexión de un grupo.

Cuestiones relacionadas