Pregunta

Considere 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 PreparedStatement.close () y ResultSet.close () arrojan un java.sql.SQLException . Entonces, ¿agrego un bloque try / catch a la cláusula finalmente? ¿O mover las declaraciones cercanas a la cláusula try? ¿O simplemente no te molestas en llamar cerca?

¿Fue útil?

Solución

Para E / S de archivo, generalmente agrego un try / catch al bloque final. Sin embargo, debe tener cuidado de no lanzar ninguna excepción desde el bloque final, ya que causarán que se pierda la excepción original (si la hubiera).

Consulte este artículo para obtener un ejemplo más específico del cierre de la conexión de la base de datos.

Otros consejos

En Java 7, no debe cerrarlos explícitamente, sino usar automático gestión de recursos para garantizar que recursos están cerrados y las excepciones se manejan adecuadamente. 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 un 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 nulas.

El ejemplo que mostraré podría verse feo con el anidamiento profundo, pero en la práctica, el código bien diseñado probablemente no va a crear una conexión, una declaración y resultados en el mismo método; a menudo, cada nivel de anidamiento implica pasar un recurso a otro método, que lo utiliza como fábrica para otro recurso. Con este enfoque, las excepciones de un close () enmascararán una excepción dentro del bloque try . Eso se puede superar, pero da como resultado un código aún más desordenado y requiere una clase de excepción personalizada que proporciona el "suprimido". Cadena de excepciones presente en Java 7.

Connection db = ds.getConnection();
try {
  PreparedStatement ps = ...;
  try {
    ResultSet rs = ...
    try {
      ...
    }
    finally {
      rs.close();
    }
  } 
  finally {
    ps.close();
  }
} 
finally {
  db.close();
}

Si realmente estás rodando tu propio jdbc, definitivamente se vuelve desordenado. El close () en el finalmente necesita ser envuelto con su propio try catch, que, al menos, es feo. No puede omitir el cierre, aunque los recursos se borrarán cuando se cierre la conexión (lo que podría no ser inmediato, si está utilizando un grupo). En realidad, uno de los principales puntos de venta del uso de un marco (por ejemplo, hibernar) para administrar su acceso db es administrar la conexión y el manejo del conjunto de resultados para que no se olvide de cerrar.

Puede hacer algo simple como esto, que al menos oculta el desorden y garantiza que no olvidará algo.

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

finally {
    close(rs, ps, null); 
}

No pierda su tiempo codificando la gestión de excepciones de bajo nivel, use una API de nivel superior como Spring-JDBC, o un contenedor personalizado alrededor de los objetos de conexión / declaración / rs, para ocultar el código desordenado try-catch montado.

También tenga en cuenta:

" Cuando un objeto Statement está cerrado, su objeto ResultSet actual, si existe, también está cerrado. "

http: // java.sun.com/j2se/1.5.0/docs/api/java/sql/Statement.html#close ()

Debería ser suficiente cerrar solo el PreparedStatement en un finalmente, y solo si aún no está cerrado. Sin embargo, si desea ser realmente particular, cierre el ResultSet FIRST, no después de cerrar el PreparedStatement (cerrarlo después, como algunos de los ejemplos aquí, debería garantizar una excepción, ya que ya está cerrado).

Por lo general, tengo un método de utilidad que puede cerrar cosas como esta, incluido el cuidado de no intentar hacer nada con una referencia nula.

Por lo general, si close () arroja una excepción, en realidad 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 sea fácil de llamar, ya que es posible que deba hacerlo en muchos lugares.

Tenga en cuenta que su solución actual no cerrará ResultSet si falla el cierre de PreparedStatement; es mejor usar bloques finalmente anidados.

Si está utilizando Java 7, puede usar las mejoras en los mecanismos de manejo de excepciones en aquellas clases que implementan AutoCloseable (es decir, PreparedStatement , Resultset )

También puede encontrar esta pregunta interesante: Conjunto de resultados de cierre en Java 7

Sé que esta es una vieja pregunta, pero en caso de que alguien esté buscando la respuesta, Java ahora tiene la solución de prueba con recursos.

static String readFirstLineFromFile(String path) throws IOException {
      try (BufferedReader br =
                   new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }
}

No omita llamar al cierre. Puede causar problemas.

Prefiero agregar el bloque try / catch al finalmente.

Probablemente una forma antigua (aunque simple) de hacer las cosas, pero aún 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();
        }               
    }
}

Basándose en la respuesta de @ erickson, ¿por qué no hacerlo en un bloque 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 los < El objeto code> PreparedStatement está cerrado.

  

Un objeto ResultSet se cierra automáticamente cuando el objeto Statement   que se genera 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

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 & amp; atrapar de nuevo en la cláusula fainlly.

Segundo, haga rs.close () antes de hacer ps.close ().

fly1997@naver.com

Yo uso esto ..

finally
{
    if (ps != null) ps.close();
    if (rs != null) rs.close();
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top