preparedstatement - prepared statement mysql java select
¿Dónde cerrar java PreparedStatements y ResultSets? (13)
Considera el código:
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.createStatement(myQueryString);
rs = ps.executeQuery();
// process the results...
} catch (java.sql.SQLException e) {
log.error("an error!", e);
throw new MyAppException("I''m sorry. Your query did not work.");
} finally {
ps.close();
rs.close();
}
Lo anterior no se compila, porque tanto PreparedStatement.close()
como ResultSet.close()
arrojan java.sql.SQLException
. Entonces, ¿agrego un bloque try / catch a la cláusula finally? ¿O mover las declaraciones cercanas a la cláusula try? ¿O simplemente no te molestes en llamar de cerca?
Basándose en la respuesta de @ erickson, ¿por qué no solo hacerlo en un bloque de try
como este?
private void doEverythingInOneSillyMethod(String key) throws MyAppException
{
try (Connection db = ds.getConnection();
PreparedStatement ps = db.prepareStatement(...)) {
db.setReadOnly(true);
ps.setString(1, key);
ResultSet rs = ps.executeQuery()
...
} catch (SQLException ex) {
throw new MyAppException("Query failed.", ex);
}
}
Tenga en cuenta que no necesita crear el objeto ResultSet
dentro del bloque try
ya que los ResultSet
se cierran automáticamente cuando se cierra el objeto PreparedStatement
.
Un objeto ResultSet se cierra automáticamente cuando el objeto Statement que lo generó se cierra, se vuelve a ejecutar o se usa para recuperar el siguiente resultado de una secuencia de resultados múltiples.
Referencia: https://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html
En Java 7, no debe cerrarlos explícitamente, sino usar la administración automática de recursos para garantizar que los resources se cierren y que las excepciones se manejen de manera adecuada. El manejo de excepciones funciona así:
Exception in try | Exception in close | Result -----------------+--------------------+---------------------------------------- No | No | Continue normally No | Yes | Throw the close() exception Yes | No | Throw the exception from try block Yes | Yes | Add close() exception to main exception | | as "suppressed", throw main exception
Espero que tenga sentido. En permite código bonito, como este:
private void doEverythingInOneSillyMethod(String key)
throws MyAppException
{
try (Connection db = ds.getConnection()) {
db.setReadOnly(true);
...
try (PreparedStatement ps = db.prepareStatement(...)) {
ps.setString(1, key);
...
try (ResultSet rs = ps.executeQuery()) {
...
}
}
} catch (SQLException ex) {
throw new MyAppException("Query failed.", ex);
}
}
Antes de Java 7, es mejor usar bloques finalmente anidados, en lugar de probar referencias para nulo.
El ejemplo que mostraré puede parecer feo con el anidamiento profundo, pero en la práctica, un código bien diseñado probablemente no va a crear una conexión, una declaración y resultados, todo en el mismo método; a menudo, cada nivel de anidación implica pasar un recurso a otro método, que lo usa como una fábrica para otro recurso. Con este enfoque, las excepciones de close()
enmascararán una excepción desde dentro del bloque try
. Eso se puede superar, pero resulta en un código aún más desordenado, y requiere una clase de excepción personalizada que proporcione el encadenamiento de excepción "suprimida" presente en Java 7.
Connection db = ds.getConnection();
try {
PreparedStatement ps = ...;
try {
ResultSet rs = ...
try {
...
}
finally {
rs.close();
}
}
finally {
ps.close();
}
}
finally {
db.close();
}
No omita llamar cerca. Puede causar problemas.
Prefiero agregar el bloque try / catch al final.
No pierda el tiempo codificando la administración de excepciones de bajo nivel, use una API de nivel superior como Spring-JDBC o un contenedor personalizado alrededor de objetos de conexión / declaración / rs, para ocultar el código desordenado try-catch montado.
Normalmente tengo un método de utilidad que puede cerrar cosas como esta, incluyendo tener cuidado de no intentar hacer nada con una referencia nula.
Por lo general, si close()
arroja una excepción, realmente no me importa, así que solo registro la excepción y la trago, pero otra alternativa sería convertirla en una RuntimeException
. De cualquier manera, recomiendo hacerlo en un método de utilidad que es fácil de llamar, ya que es posible que deba hacer esto en muchos lugares.
Tenga en cuenta que su solución actual no cerrará ResultSet si el cierre de PreparedStatement falla; es mejor utilizar bloques finalmente anidados.
Para E / S de archivos, generalmente agrego un try / catch al bloque finally. Sin embargo, debe tener cuidado de no lanzar ninguna excepción desde el bloque finally, ya que harán que se pierda la excepción original (si la hay).
Vea este artículo para un ejemplo más específico de cierre de conexión de base de datos.
Probablemente una forma antigua (aunque simple) de hacer las cosas, pero todavía funciona:
public class DatabaseTest {
private Connection conn;
private Statement st;
private ResultSet rs;
private PreparedStatement ps;
public DatabaseTest() {
// if needed
}
public String getSomethingFromDatabase(...) {
String something = null;
// code here
try {
// code here
} catch(SQLException se) {
se.printStackTrace();
} finally { // will always execute even after a return statement
closeDatabaseResources();
}
return something;
}
private void closeDatabaseResources() {
try {
if(conn != null) {
System.out.println("conn closed");
conn.close();
}
if(st != null) {
System.out.println("st closed");
st.close();
}
if(rs != null) {
System.out.println("rs closed");
rs.close();
}
if(ps != null) {
System.out.println("ps closed");
ps.close();
}
} catch(SQLException se) {
se.printStackTrace();
}
}
}
Sé que esta es una vieja pregunta, pero por si alguien está buscando la respuesta, java ahora tiene la solución try-with-resouce.
static String readFirstLineFromFile(String path) throws IOException {
try (BufferedReader br =
new BufferedReader(new FileReader(path))) {
return br.readLine();
}
}
Si está utilizando Java 7, puede usar las mejoras en los mecanismos de manejo de excepciones en aquellas clases que implementan resources (es decir, PreparedStatement
, Resultset
)
También puede encontrar esta pregunta interesante: Cierre ResultSet en Java 7
Si realmente estás moviendo a mano tu propia jdbc definitivamente se vuelve desordenada. El close () en el final necesita envolverse con su propia captura de prueba, que, como mínimo, es fea. No puede omitir el cierre, aunque los recursos se borrarán cuando se cierre la conexión (lo que podría no ocurrir de inmediato, si está utilizando un grupo). En realidad, uno de los principales puntos de venta de usar un marco (por ejemplo, hibernación) para administrar su acceso de acceso directo es administrar la conexión y el manejo del conjunto de resultados para que no se olvide de cerrar.
Puedes hacer algo tan simple como este, que al menos oculta el desorden y te garantiza que no te olvides de nada.
public static void close(ResultSet rs, Statement ps, Connection conn)
{
if (rs!=null)
{
try
{
rs.close();
}
catch(SQLException e)
{
logger.error("The result set cannot be closed.", e);
}
}
if (ps != null)
{
try
{
ps.close();
} catch (SQLException e)
{
logger.error("The statement cannot be closed.", e);
}
}
if (conn != null)
{
try
{
conn.close();
} catch (SQLException e)
{
logger.error("The data source connection cannot be closed.", e);
}
}
}
y entonces,
finally {
close(rs, ps, null);
}
También tenga en cuenta:
"Cuando se cierra un objeto Statement, su objeto actual ResultSet, si existe, también se cierra".
http://java.sun.com/j2se/1.5.0/docs/api/java/sql/Statement.html#close()
Debería ser suficiente para cerrar solo el PreparedStatement por fin, y solo si aún no está cerrado. Sin embargo, si quiere ser realmente particular, cierre el ResultSet FIRST, no después de cerrar PreparedStatement (cerrarlo después, como algunos de los ejemplos aquí, debería garantizar una excepción, dado que ya está cerrado).
Yo uso esto..
finally
{
if (ps != null) ps.close();
if (rs != null) rs.close();
}
foco, finalmente, cláusula
finally {
try {
rs.close();
ps.close();
} catch (Exception e) {
// Do something
}
}
Creo que tienes que modificar 2 puntos.
Primero, use try & catch nuevamente en la cláusula fainlly.
Segundo, haga rs.close () antes de hacer ps.close ().