2011-01-12 9 views
5

Zamiast skomplikowanych kwerend SQL, prób, catch i finałów wszędzie w kodzie mam metodę execute(SQL, up to three inputs), jednak jeśli próbuję uzyskać dostęp do zestawu wyników, który generuje poza wykonaniem, które otrzymujesz błąd:Java Używanie metody SQL Execute, ale możliwość uzyskiwania dostępu do wyników

"Operation not allowed after ResultSet closed" 

Który ponieważ po zamknięciu PreparedStatement zamyka ResultsSetToo (i nie wydaje się być w żaden sposób wokół niego).

Czy istnieje sposób, aby to naprawić? Jedyne, co myślę było przekształcenie go do tablicy, która jest przechowywana

Wielkie dzięki za poświęcony czas,

Odpowiedz

9

Napotkałem ten sam problem w przeszłości. Teraz mogę używać tej metody:

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

Zamiast zwracania ResultSet, zwraca listę mapy (każdy reprezentujący 1 wiersz). Pierwszy ciąg to kolumna Etykieta, a drugi to wartość kolumny. Mam nadzieję, że to pomoże. :-)

+0

Powinieneś przekazać 'Map ', aby uniknąć utraty informacji o rzeczywistych zwracanych typach danych. Natomiast 'rs.getObject (1) .toString()' zbombarduje wyjątek NullPointerException, jeśli tabela zawiera wartości NULL. –

+0

Wszystkie odwzorowane typy JDBC mają metodę toString(). I o wartości zerowej, nie miałem żadnych problemów. SELECT * Z jednego z moich tabel, w którym znajduje się pole DATE z wartościami pustymi, wypisuje "null" na konsoli. – athspk

+0

Oczywiście mają metodę toString(). Ale konwersja Stringa z powrotem do "prawdziwej" rzeczy może być problemem.Skąd wiesz, do którego obiektu mają zostać przekonwertowane? Co z domyślnym formatowaniem, które zależy od ustawień narodowych (separator dziesiętny, format daty i tak dalej). To tak jak przechowywanie wszystkiego w kolumnie varchar w bazie danych ... –

4

when you close the PreparedStatement it closes the ResultsSetToo

Prawidłowe. Więc nie możesz zamykać PreparedStatement, dopóki nie przetworzysz wyniku.

Chciałbym zdefiniować interfejs, np. ResultConsumer lub coś podobnego, które może wywołać wywołujący execute(). Następnie wewnątrz metody execute() wystarczy przekazać zestaw wyników do konsumenta.

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

wówczas execute() może wyglądać tak

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

(Usunąłem wszystkie sprawdzanie błędów i obsługę wyjątków dla jasności, oczywiście trzeba sobie z tym poradzić)

+0

Przejście w takim zamknięciu jest świetnym sposobem na poradzenie sobie z tym. Jeśli nadal chcesz przechowywać dane w pobliżu, możesz napisać ogólne zamknięcie, aby umieścić wyniki w postaci listy lub przeczytać ją później, jeśli chcesz. – jricher

4

Jakiś czas temu miałem ten sam problem, z którym miałem do czynienia. Po pewnym zastanowieniu nad tym projektem postanowiliśmy zrobić to jak poniżej.

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

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

    return resulProperties; 

} 

Z jakiegoś konkretnego powodu, stworzyłem pole w mojej klasie, jak podano poniżej

private static ExecuteRequest er = new ExecuteRequest(); 

W ExecuteRequest klasa poniżej kod jest używany.

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; 

} 

Możesz użyć tego podejścia jako rozwiązania.

Powiązane problemy