Nested resultsets

Estou o obtendo o erro The result set is closed no código abaixo:


public List retornaCategorias() throws Exception {
         Statement stmt = null;
         PreparedStatement pstmt = null;
         ResultSet rset = null;
         ResultSet rsImagem = null;
         try {
             
             String sb = null;
             String comandoSQL = null;
           
             sb = "select * from grupo  where not (nome_grupo is null) order by nome_grupo desc ";  
             comandoSQL = "select count(*) as total from produto where cp_grupo = ? and ( not cp_imgprod is null)";
                                    
                                 
             stmt = conn.createStatement();
             pstmt = conn.prepareStatement(comandoSQL);
                     
             
             rset = stmt.executeQuery(sb);
             List<Categoria> categorias = new ArrayList<Categoria>();
             
             Categoria umaCategoria;
             
           while (rset.next()) {
               umaCategoria = new Categoria();
               umaCategoria.setDescricao(rset.getString("nome_grupo"));
               umaCategoria.setId(rset.getInt("cp_grupo"));
                           
               pstmt.setInt(1,umaCategoria.getId());
               rsImagem = pstmt.executeQuery();
               if (rsImagem.next()) {                                
                  if (rsImagem.getInt("total") > 0) {                                
                  categorias.add(umaCategoria);            
                  }
               }               
              
               
           }
           return categorias;
           
         } finally {
             if (rset != null) try { rset.close(); } catch(Exception e) { }
             if (stmt != null) try { stmt.close(); } catch(Exception e) { }
         }
     
    }    

este erro acontece na segunda iteração do loop mais externo. precisamente na linha while (rset.next())

Nesse código, abro um resultset e com dados desse abro outro aninhadamente…
Parece que quando ele chega ao fim do resultset interno ele fecha o primeiro!
Será que eu teria que usar uma connection para cada resultset?

Alguem tem alguma idéia?

Hübner (ETI)

Está dando alguma excessão e você não está capturando ela.

Usa um catch ao invés de passar a excessão para o método chamador e analisa ela usando:

System.out.println( exc.getMessage() ); exc.printStackTrace();

Pelo erro que você mencionou, parece que você já está fazendo isso. Sendo assim dá uma olhada se suas queries estão corretas e se estáo retornando valores ou não.

Mas uma coisa, prefira usar somente o PreparedStatement ao invés do Statement.

Tenta ir depurando o código parte por parte para ver onde está o problema. Vc pode depurar usando um depurador mesmo, ou então ir removendo algumas linhas de código para achar onde está enroscando.

Já vi este erro acontecer quando o result set vem vazio e vc tenta dar o next(), por isso falei para vc ver se as queries (a externa) está correta.

Falow!

Olá David,

Os dois selects estão ok, já os testei com a ferramenta isql do banco. Pesquisando na web, li em algum lugar que esse problema parece ser do driver jdbc e/ou banco.

Cara, eu custo acreditar que esse tipo de problema possa ocorrer num código super comum (Processar uma lista dentro da outra). Eu faço isso corriqueiramente, todos os dias com delphi…

Deve haver algum mecanismo, parametro para aqueles prepareStatement para isso ser possível…

vou pesquisar mais… se souber de algo nesse sentido posta ai pra nós…

Obrigado

Hübner (ETI)

Inclua o código

pstmt = conn.prepareStatement(comandoSQL);

dentro do while.

O objeto ResultSet é intimamente ligado ao Statement que o criou, portanto não reaproveite Statement’s.

De qualquer maneira, “result set closed” pode ocorrer em alguns drivers JDBC como o do DB2 quando você tenha aninhar um resultset dentro do outro.

Olá thingol,

não faz sentido usar preparedStatement repetidamente dentro de loops, já que a idéia é preparar a sua query uma única vez no bd e usá “compilada” passando somente seus parametros… . Do jeito que vc sugeriu não funcionou, mas de qualquer forma obrigado a todos que se empenharam em ajudar…

Consegui resolver o meu problema usando a interface CachedRowSet. A implementação dessa interface gera um rowset desconectado do banco o que permite que vc itere pelo mesmo sem ser afetado pelas operações de resultsets internos ao loop. Além do mais ele possui cursores pra frente e para traz dando maior flexibilidade para se trabalhar em algoritmos.

Para usá-lo são necessário os seguinte imports:


 import javax.sql.rowset.CachedRowSet;
 import com.sun.rowset.CachedRowSetImpl;
 

 
 public List retornaCategorias() throws Exception {
         Statement stmt = null;
         PreparedStatement pstmt = null;
         ResultSet rsImagem =  null;
         ResultSet rset;
         try {
             
             String comandoSQLCached = null;
             String comandoSQL = null;
           
             comandoSQLCached = "select * from grupo where not nome_grupo is null order by nome_grupo";          
             comandoSQL = "select count(*) as total from produto where cp_grupo = ? and ( not cp_imgprod is null) ";
                                                          
             stmt = conn.createStatement();                              // prepara o statement da query  
             rset = stmt.executeQuery(comandoSQLCached);                 // executa a query          
             CachedRowSet crs = new CachedRowSetImpl();                  // cria o CachedRowSet
             crs.populate(rset);                                         // preenche com dados do resultado da query
             
             pstmt = conn.prepareStatement(comandoSQL);                  // prepara p statement parametrizado  
             List categorias = new ArrayList();    // cria a lista a ser populada
             
             Categoria umaCategoria;                                     // item da lista
             
           while (crs.next()) {                                          // itera pelo CachedRowSet
               umaCategoria = new Categoria();
               umaCategoria.setDescricao(crs.getString("nome_grupo"));
               umaCategoria.setId(crs.getInt("cp_grupo"));                          
               pstmt.setInt(1,umaCategoria.getId());
               rsImagem = pstmt.executeQuery();
               if (rsImagem != null) {
                   if (rsImagem.next()) {
                       if ((rsImagem.getInt("total") > 0)) {
                          categorias.add(umaCategoria);      
                       }
                   }
               }
           }
           return categorias;
           
         } finally {
             if (rset != null) try { rset.close(); } catch(Exception e) { }           
             if (stmt != null) try { stmt.close(); } catch(Exception e) { }
             if (pstmt != null) try { pstmt.close(); } catch(Exception e) { }
         }
     
    }
 

Nos testes que fiz não detectei nenhuma perda de performance.

Obrigado.

Hübner