2011-01-12 7 views
5

Anstatt komplexe SQL-Abfragen, versucht, fangen und Finale überall im Code habe ich eine Methode execute(SQL, up to three inputs) jedoch, wenn Sie versuchen, Zugriff auf die ResultsSet erzeugt außerhalb der Ausführung erhalten Sie der Fehler:Java Mit SQL Execute Methode, aber auf Ergebnisse zugreifen

"Operation not allowed after ResultSet closed" 

Was ist denn, wenn Sie die PreparedStatement schließen sie die ResultsSetToo schließt (und es scheint sich um sie keine Möglichkeit zu sein).

Gibt es eine Möglichkeit, das zu beheben? Das einzige, was ich denken konnte, war es zu einem Array umzuwandeln, die

Vielen Dank für Ihre Zeit gespeichert ist,

Antwort

9

Ich habe das gleiche Problem in der Vergangenheit angetroffen. Jetzt benutze ich diese Methode:

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

Statt eine ResultSet zurückzukehren, hat es eine Liste von Karten gibt (jeweils entsprechend 1 Reihe). Der erste String ist die Spalte Label und der zweite der Wert der Spalte. Ich hoffe, es hilft. :-)

+0

Sie sollten eine 'Map ' zurückgeben, um zu vermeiden, dass Informationen über die tatsächlichen zurückgegebenen Datentypen verloren gehen. Und 'rs.getObject (1) .toString()' wird mit einer NullPointerException bombardieren, wenn die Tabelle NULL-Werte enthält. –

+0

Alle zugeordneten JDBC-Typen verfügen über eine toString() -Methode. Und über die Null habe ich keine Probleme gehabt. SELECT * Aus einer meiner Tabellen, in der es ein DATE-Feld mit Nullwerten gibt, wird "Null" auf der Konsole ausgegeben. – athspk

+0

Natürlich haben sie eine toString() -Methode. Aber das Konvertieren des Strings zurück zum "echten" Ding könnte ein Problem sein.Woher weißt du, zu welchem ​​Objekt sie zurück konvertiert werden sollen? Was ist mit der Standardformatierung, die vom Gebietsschema abhängt (Dezimaltrennzeichen, Datumsformate usw.)? Das ist so, als würde man alles in einer varchar-Spalte in der Datenbank speichern ... –

4

when you close the PreparedStatement it closes the ResultsSetToo

Richtig. Das PreparedStatement darf daher erst geschlossen werden, wenn Sie das Ergebnis verarbeitet haben.

Ich würde eine Schnittstelle definieren, z. ResultConsumer oder etwas ähnliches, das der Aufrufer von execute() implementieren kann. Dann übergeben Sie innerhalb Ihrer execute() -Methode das Resultset einfach an den Konsumenten.

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

Dann führen Sie Ihre() könnte so aussehen wie

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

(Ich entfernte alle Fehlerprüfung und Ausnahme für Klarheit Handhabung, natürlich werden Sie damit umgehen müssen)

+0

Das Übergeben einer solchen Schließung ist eine großartige Möglichkeit, damit umzugehen. Wenn Sie die Daten immer noch behalten möchten, können Sie eine generische Closure schreiben, um die Ergebnisse in eine Liste zu schreiben oder etwas, um es später zu lesen, wenn Sie möchten. – jricher

4

Vor einiger Zeit war ich in demselben Problem, mit dem ich mich befassen musste. Nachdem wir über dieses Design nachgedacht hatten, beschlossen wir, es wie unten zu tun.

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

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

    return resulProperties; 

} 

Aus irgendeinem bestimmten Grund, habe ich in meiner Klasse ein Feld unter

verwendet
private static ExecuteRequest er = new ExecuteRequest(); 

In ExecuteRequest Klasse Code unten als gegeben.

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; 

} 

Sie können diesen Ansatz als Lösung verwenden.