2011-01-12 10 views
5

複雑なSQLクエリー、試行、キャッチ、ファイナルをコード内のどこにでも持つのではなく、私はメソッドexecute(SQL, up to three inputs)を持っていますが、エラー:あなたはPreparedStatementを閉じたときに、それはResultsSetTooをクローズ(およびその周辺のない方法はないように思える)ためであるJava SQL実行メソッドを使用しているが結果にアクセスできる

"Operation not allowed after ResultSet closed" 

これを修正する方法はありますか?私は考えることができる唯一の事は正しいお時間を

多くのおかげで、

答えて

9

過去に同じ問題が発生しました。今、私はこの方法を使用:代わりResultSetを返す

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

を、それが地図(1行を表すそれぞれ)のリストを返します。最初のStringは列Labelで、2番目のStringは列の値です。私はそれが助けて欲しい:-)

+0

返される実際のデータ型に関する情報が失われないように、 'Map 'を返すべきです。テーブルにNULL値が含まれていると、 'rs.getObject(1).toString()'はNullPointerExceptionで爆発します。 –

+0

マップされたすべてのJDBC型には、toString()メソッドがあります。そしてヌルについては、何の問題もありませんでした。 SELECT *ヌル値を持つDATEフィールドがある私のテーブルの1つから、コンソールに "null"が表示されます。 – athspk

+0

もちろんtoString()メソッドがあります。しかし、文字列を「本当の」ものに変換することは問題になるかもしれません。どのオブジェクトを元に戻すべきか、どのように知っていますか?ロケールに依存するデフォルトの書式設定(小数点記号、日付書式など)はどうでしょうか。これはデータベースのvarcharカラムにすべてを保存するのと同じです... –

4

when you close the PreparedStatement it closes the ResultsSetToo

の格納された配列に変換しました。結果を処理するまで、PreparedStatementを閉じることはできません。

私はインターフェースを定義します。 ResultConsumerまたはexecute()の呼び出し側が実装できるようなもの。 execute()メソッドの中で、単にResultsetをコンシューマに渡します。

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

次に、あなたが実行()この

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

(私はわかりやすくするために処理し、すべてのエラーチェックと例外を削除し、もちろんあなたはそれに対処する必要があります)

+0

このようなクロージャを渡すと、これを処理するのに最適です。それでもデータを保持したい場合は、結果をリストなどにスローするための包括的クロージャーを書いたり、必要に応じて後で読むことができます。 – jricher

4

ようになります。何度か戻って、私は同じ問題に対処していました。このデザインを熟考した後、私たちはそれを以下のようにすることに決めました。いくつかの具体的な理由については

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

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

    return resulProperties; 

} 

コードの下ExecuteRequestクラスで

private static ExecuteRequest er = new ExecuteRequest(); 

以下に示すように、私は私のクラスのフィールドを作成したが使用されています。

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; 

} 

このアプローチをソリューションとして使用できます。