2011-01-12 10 views
5

En lugar de tener consultas SQL complejas, intentos, capturas y finales en todas partes del código, tengo un método execute(SQL, up to three inputs), sin embargo, si intenta acceder al ResultsSet esto produce fuera de la ejecución que obtiene el error:Java utilizando el método SQL Execute pero pudiendo acceder a los resultados

"Operation not allowed after ResultSet closed" 

Cuál es porque cuando se cierra el PreparedStatement se cierra la ResultsSetToo (y no parece haber ninguna manera de evitarlo).

¿Hay alguna manera de arreglar esto? El único que podía pensar era convertirlo en una matriz que se almacena

Muchas gracias por su tiempo,

Respuesta

9

He encontrado el mismo problema en el pasado. Ahora uso este método:

public ArrayList<Map<String, String>> getListOfMapsFromSQL(String sql) throws SQLException { 
    con = DriverManager.getConnection(url,user,pass); 
    stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE); 
    ArrayList<Map<String, String>> list = new ArrayList<Map<String, String>>(); 

    rs = stmt.executeQuery(sql); 
    ResultSetMetaData rsmd = rs.getMetaData(); 

    while(rs.next()){ 
     Map<String, String> fieldsMap = new HashMap<String, String>(); 
     for(int i=1; i<=rsmd.getColumnCount(); i++){ 
      fieldsMap.put(rsmd.getColumnLabel(i), rs.getObject(i).toString()); 
     } 
     list.add(fieldsMap); 
    } 

    list.trimToSize(); 
    stmt.close(); 
    con.close(); 
    return list; 
} 

En lugar de devolver un ResultSet, devuelve una lista de mapas (cada uno representando 1 fila). La primera Cadena es la Etiqueta de la columna, y la segunda es el valor de la columna. Espero que ayude. :-)

+0

Debe devolver un 'Map ' para evitar perder información sobre los tipos de datos reales devueltos. Y 'rs.getObject (1) .toString()' saltará con una NullPointerException si la tabla contiene valores NULL. –

+0

Todos los tipos JDBC mapeados tienen un método toString(). Y sobre el nulo, no he tenido ningún problema. SELECCIONAR * Desde una de mis Tablas donde hay un campo FECHA con valores nulos, imprime "nulo" en la consola. – athspk

+0

Por supuesto, tienen un método toString(). Pero convertir el String a lo "real" podría ser un problema.¿Cómo se sabe a qué objeto se deben convertir? ¿Qué pasa con el formato predeterminado que depende de la configuración regional (separador decimal, formatos de fecha, etc.)? Esto es como almacenar todo en una columna varchar en la base de datos ... –

4

when you close the PreparedStatement it closes the ResultsSetToo

correcta. Por lo tanto, no puede cerrar PreparedStatement hasta que haya procesado el resultado.

Definiría una interfaz, p. ResultConsumer o algo similar que la persona que llama de execute() puede implementar. Luego, dentro de su método execute() simplemente transfiere el conjunto de resultados al consumidor.

 
public Interface ResultConsumer 
{ 
    void processResult(ResultSet rs); 
} 

Luego, su execute() podría tener este aspecto

 
public void execute(String SQL, ResultConsumer consumer, ... other parameters) 
{ 
    PreparedStatement stmt = ... 
    ResultSet rs = stmt.executeQuery(); 
    consumer.processResult(rs); 
    rs.close(); 
    stmt.close(); 
} 

(He quitado todo comprobación de errores y la gestión de excepciones por motivos de claridad, por supuesto que necesita para hacer frente a eso)

+0

Pasar por un cierre como ese es una gran manera de manejar esto. Si aún desea conservar los datos, podría escribir un cierre genérico para arrojar los resultados en una lista o algo así para leerlo más tarde, si lo desea. – jricher

4

Hace un tiempo, tenía el mismo problema que enfrentar. Después de reflexionar sobre este diseño, decidimos hacerlo a continuación.

public static Properties execute(String string, String[] columnames) throws Exception { 

    Properties resulProperties = er.executeQuery(string, columnames); 

    return resulProperties; 

} 

Por alguna razón específica, he creado un campo en mi clase como se indica a continuación

private static ExecuteRequest er = new ExecuteRequest(); 

En clase se utiliza ExecuteRequest continuación código.

public Properties executeQuery(String sqlstatement, String[] columnNames) throws Exception { 
    Properties prop = new Properties(); 
    try { 
     prop = creteProperty(sqlstatement, columnNames); 
    } catch (Exception e) { 
     mlogger.report("Error executing sql statement"); 
     throw (e); 
    } 

    return prop; 

} 

public Properties creteProperty(String sqlstatement, String[] columnNames) throws Exception { 
    Properties prop = new Properties(); 

    try { 
     PreparedStatement stmt = ConnectionManager.getInstance().prepareStatement(sqlstatement); 
     ResultSet rs = stmt.executeQuery(); 
     if (rs.next()) { 
      for (int i = 0; i < columnNames.length; i++) { 
       String key = columnNames[i]; 
       if (rs.getObject(key) != null) { 
        String value = (rs.getObject(key).toString()); 
        prop.setProperty(key, value); 
       } else { 
        String value = ""; 
        prop.setProperty(key, value); 
       } 

      } 
     } 
     rs.close(); 
    } catch (Exception e) { 
     mlogger.report("Error executing sql statement"); 
     throw (e); 
    } 
    return prop; 

} 

Puede utilizar este enfoque como una solución.

Cuestiones relacionadas