2011-01-12 9 views
5

Anziché avere query SQL complesse, tentativi, catch e finali ovunque nel codice, ho un metodo execute(SQL, up to three inputs) tuttavia se si tenta di accedere al ResultsSet che produce all'esterno dell'esecuzione si ottiene l'errore:Java Utilizzo del metodo SQL Execute ma accesso ai risultati

"Operation not allowed after ResultSet closed" 

che è perché quando si chiude il PreparedStatement chiude la ResultsSetToo (e sembra che ci sia alcun modo intorno ad esso).

C'è un modo per risolvere questo problema? L'unica cosa che riuscivo a pensare era convertirlo in una matrice che è memorizzato

Molte grazie per il vostro tempo,

risposta

9

ho incontrato lo stesso problema in passato. Ora, io uso questo metodo:

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

invece di restituire un ResultSet, restituisce un elenco di mappe (ognuno dei quali rappresenta 1 fila). La prima stringa è la colonna Label e la seconda è il valore della colonna. Spero possa essere d'aiuto. :-)

+0

È necessario restituire un 'Map ' per evitare di perdere informazioni sui tipi di dati effettivamente restituiti. E 'rs.getObject (1) .toString()' sarà bombardare con una NullPointerException se la tabella contiene i valori NULL. –

+0

Tutti i tipi JDBC associati hanno un metodo toString(). E sul nulla, non ho avuto problemi. SELECT * Da una delle mie tabelle in cui è presente un campo DATE con valori nulli, stampa "null" sulla console. – athspk

+0

Ovviamente hanno un metodo toString(). Ma convertire la stringa in "reale" potrebbe essere un problema.Come fai a sapere a quale oggetto dovrebbero essere riconvertiti? Che ne è della formattazione predefinita che dipende dalle impostazioni internazionali (separatore decimale, formati data e così via). Questo è proprio come memorizzare tutto in una colonna varchar nel database ... –

4

when you close the PreparedStatement it closes the ResultsSetToo

corretta. Quindi non si può chiudere il PreparedStatement fino a quando non si è elaborato il risultato.

avrei definire un'interfaccia esempio ResultConsumer o qualcosa di simile che il chiamante di execute() in grado di implementare. Quindi all'interno del tuo metodo execute() devi semplicemente passare il Resultset al consumatore.

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

Allora la vostra execute() potrebbe assomigliare a questo

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

(ho rimosso tutto il controllo degli errori e gestione delle eccezioni per chiarezza, naturalmente avrete bisogno per affrontare questo)

+0

Passando in una chiusura del genere è un ottimo modo per gestire questa situazione. Se si vuole ancora mantenere i dati in giro, si potrebbe scrivere una chiusura generico per gettare i risultati in una lista o qualcosa da leggere in un secondo momento, se vuoi. – jricher

4

Qualche tempo fa, ero nello stesso problema da affrontare. Dopo aver riflettuto su questo progetto, abbiamo deciso di farlo come di seguito.

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

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

    return resulProperties; 

} 

Per qualche motivo specifico, ho creato un campo nella mia classe, come indicato di seguito

private static ExecuteRequest er = new ExecuteRequest(); 

In è usato ExecuteRequest classe inferiore codice.

È possibile utilizzare questo approccio come soluzione.