Dúvida "teórica" resultset

11 respostas
T

Olá, sou novo no assunto, então, não achem ruim por favor de perguntas básicas, afinal estou na seção “Java BÁSICO”. :wink:

Aprendi a conexão de Java com BD recentemente (na faculdade), e estou com uma dúvida um tanto quanto teórica sobre o assunto.

Num arquivo java vazio, eu crio a conexão, abro e fecho o BD, mas estou com dúvidas no resultset.

Nesse arquivo de java vazio, eu jogo como query "SELECT * FROM " porém, só fiz exercícios onde o resultset só recebe 1 resultado (1 linha) desse BD.

Estou com dúvidas no que acontece que o retorno desse “select” é maior que 1.

PRA MIM, existe 2 modos:

1 - eu faço o resultset receber o conteúdo do resultado e envio para a parte gráfica, 1 linha do resultado por vez. Faço isso com while e repito o numero de vezes que o resultado do bd estiver de linhas.

2 - eu faço o resultset receber todos resultados e mando esse “pacote” pra parte gráfica.

3 - nenhum dos dois rs :wink:

estou na linha de pensamento correta ???

11 Respostas

rmendes08

Que fique claro: o método executeQuery do Statement deve ser executado uma única vez (isso se os parâmetros da query não mudarem), ou pelo menos, o mínimo de vezes possível. Ou seja, as chamadas através da conexão com o banco de dados devem ser as mínimas possíveis.

Quando você chama o método next() do ResultSet você posiciona o ResultSet em uma linha do resultado. Invariavelmente, você deve percorrer o ResultSet em um laço para obter todas as linhas. Se o envio dos dados para a interface deve ocorrer dentro do laço ou após o laço a resposta é: depende!. Depende do custo desse envio. Se a consulta for uma resposta a uma requisição HTTP por exemplo, o envio dos dados para o lado cliente é uma operação de alto custo, porque envolve trasmitir dados através de uma rede. Nesse caso, é muito melhor armazenar os resultados em uma coleção e enviar a coleção de uma única vez. Por outro lado, se esse envio for simplesmente setar propriedades de componentes gráficos na mesma aplicação, o custo é insignificante, e nesse caso pode ser interessante economizar a criação de um objeto de coleção somente para “pendurar” esses dados.

Bem, espero que você tenha entendido, e lembre-se que isso é só um exemplo, não precisa tomar como regra geral.

T

"você deve percorrer o ResultSet em um laço para obter todas as linhas"

Estou achando essa parte meio complexa.

public boolean pesquisa()
    {
        boolean conseguiu = false;

        String query = "SELECT * FROM tabela";

        try
        {
            resultset = statement.executeQuery(query);

            while(resultset.next())
            {
                conseguiu = true;

                codigo = resultset.getString("CODIGO");
                nome = resultset.getString("NOME");
                salario = resultset.getString("SALARIO");
            }
        }
            catch(Exception e)
        {
            JOptionPane.showMessageDialog(null,"Error "+e);
        }

        return conseguiu;
    }

public String retorna1()
    {
        return codigo;
    }
    public String retorna2()
    {
        return nome;
    }
    public String retorna3()
    {
        return salario;
    }

e na gráfica

fb = new formBanco();

    fb.OpenDB();
        
    DefaultTableModel modelo = (DefaultTableModel) tabela.getModel();
    
    fb.pesquisa();
    
    modelo.addRow(new Object [] {fb.retorna1(),fb.retorna2(),fb.retorna3()});

onde exatamente eu jogo esse laço pro resultset receber vários resultado ?

T

Desculpem, eu nao expliquei o que eu tentei fazer.

Adicionei manualmente conteúdos no banco de dados, e estou tentando jogá-los numa tabela (o bd tem as mesmas colunas que a tabela)

Do jeito que está ai em cima, eu consigo adicionar à tabela apenas a ÚLTIMA linha do BD, ou seja, ele está substituindo os resultsets anteriores

AlexandreGama

Só bati o olho, mas da forma que está seu código realmente ele só mostrará o último resultado.
Você fez um while

while(resultset.next())  
            {  
                conseguiu = true;  
  
                codigo = resultset.getString("CODIGO");  
                nome = resultset.getString("NOME");  
                salario = resultset.getString("SALARIO");  
            }

Mas depois que você sai dele você só tem o último código nas suas Strings.

Uma das formas de você fazer:
Em vez de atribuir para Strings os valores do ResultSet (codigo, nome e salario)
Atribua a uma lista de objetos. A partir do seu formulário você acessa sua lista e
preenche a sua tabela.

Você poderia ter List (imaginei um objeto Funcionário para as suas propriedades codigo, nome e salario)
e popularia esta lista.
Quando você for preencher a sua tabela você faz um while, percorrendo todos os funcionários.
Esta é só uma maneira simples de se fazer.
O que acha?

Até mais!

AlexandreGama

Um outra forma, não sei se menos incomum(tenho pouca experiência com Swing)
é você usar o setDataVector()
Se eu não me engano, basicamente você precisa de um Vector() para os títulos
e um Vector() para as linhas.

Você teria algo como:

titulos = new Vector(3);
titulos.add("Codigo");
titulos.add("Nome");
titulos.add("Salario");

linhas = new Vector(3);
linhas.add("SeuCodigo");
linhas.add("SeuNome");
linhas.add("SeuSalario");

modelo.setDataVector(linhas, titulos);

Como faz muito tempo que já fiz algo assim, realmente não lembro bem se essa forma é permitida.
Mas algúem do Guj mais experiente vai poder te ajudar nesta dica e me fazer lembrar também! :wink:

Até mais!

ViniGodoy

Primeiro de tudo, você deve criar uma classe para representar seus dados. Por exemplo, digamos que sua classe represente funcionários.

public class Funcionario {
   private int codigo;
   private String nome;
   private double salario;

   public Funcionario(int codigo, String nome, double salario) {
      this.nome = nome;
      this.codigo = codigo;
      this.salario = salario;
   }

   public int getCodigo() { return codigo; }
   public String getNome() { return nome; }
   public double getSalario() { return salario; }
}
Note que é muito importante trabalhar com os tipos de dados corretos. Nome é um String, mas o código é inteiro e o salário é um double (a rigor, seria melhor representa-lo como BigDecimal, mas não usei a classe aqui para simplicidade do exemplo).

O importante é você entender que os dados só serão Strings em um único lugar: dentro dos seus objetos de view (TextFields, labels, etc).

2. O segundo passo é você fazer com que sua classe que controla o banco de dados (DAO), carregue um List de objetos da sua classe. O List é muito parecido com o Vector, que o colega acima citou, mas não é sincronizado. O uso do Vector não é recomendado desde o Java 1.2, e essa classe só se mantém na API por questões de compatibilidade. O código fica assim:

public List<Funcionario> carregarFuncionarios() {   
   String query = "SELECT * FROM tabela";   
  
   try {   
      try {
         statement = connection.prepareStatement(query);
         resultset = statement.executeQuery();   
  
         List<Funcionario> lista = new ArrayList<Funcionario>();
         while(resultset.next()) {   
            Funcionario f = new Funcionario(
               resultset.getInt("CODIGO");   
               nome = resultset.getString("NOME");   
               salario = resultset.getDouble("SALARIO");
            );
            lista.add(f);
      }  finally {
         //É muito importante manter os recursos fechados
         statement.close();
         resultset.close();
      }
   }   catch(Exception e)   {   
      //Exibir erros é papel da view, então aqui só repassamos a exceção.
      throw new RuntimeException(e);
   }  

   return lista;   
}

Finalmente, você exibe o resultado na tela. Para isso, você não usa o DefaultTableModel. Para usar o JTable, você precisa criar um FuncionarioTableModel. Os links da minha assinatura expilcam como fazer isso. O código ficará trivial como:

try {
   FuncionarioDao dao = new FuncionarioDao();
   List<Funcionario> lista = dao.carregarFuncionarios();
   FuncionarioTableModel model = new FuncionarioTableModel(lista);
   seuJTable.setModel(model);
} catch (Exception e) {
   //Grave possíveis exceções num arquivo, com o stacktrace completo. 
   //Assim fica fácil corrigir o código se elas ocorrem.

   logarException(e); 
   //Aqui sim, na interface gráfica, exibimos o erro.
   //Podemos (e devemos) passar this no primeiro parâmetro pois estamos num JFrame ou JDialog.
   JOptionPane.showMessageDialog(this, "Ocorreram erros! " + e.getMessage());
}

Sugiro que siga esses passos, para ter um programa organizado e bem-feito. Isso poupa muitas dores de cabeça e facilita enormemente a manutenção.

AlexandreGama

Hehe, imaginei que o Vinny realmente ia chamar a atenção sobre o DefaultTableModel
que já está há um tempo na sua assinatura. :wink:
Coloquei mais pra você ter outra forma de pesquisa/estudo/curiosidade, mas como o Vinny falou (e altamente aconselhável)
não se deve usar! :slight_smile:

Como ele disse, e volto a falar, trabalhe com objetos e seus tipos corretos como ResultSet.

Abraços!

T

Eu uso DTM rs

ahh lerei com calma o que todos colocaram, por hora fiz de outro modo, fui adicionando o conteúdo da tabela dentro de um while dentro do meu arquivo java vazio, depois passei o modelo por parâmetro.

Obrigado todos ai :wink:

AlexandreGama

Olá tsalsicha!

Acho até natural usarmos, pelo menos uma vez para sentir o drama. Quando comecei a estudar Java
usei mas não usei nunca mais.
O Vinny iniciou essa discussão há algum tempo e colocou uma série de dicas interessantes,
vale a pena conferir!
Mas nada como você conhecer várias implementações da mesma situação, fazendo com que
você conheça os prós e contras da sua decisão!

Abraços!

makecio

Vejo que voce esta com pequeno problema xD

tenta fazer o seguinte passa o MODELO da tabela da parte “grafica” para sua outra classe , dentro do while vc adiciona as linhas e depois retorna o modelo.

Desse jeito…

public DefaultTableModel pesquisa(DefaultTableModel modelo)  
    {  
          
        String query = "SELECT * FROM tabela";  
  
        try  
        {  
            resultset = statement.executeQuery(query);  
  
            while(resultset.next())  
            {  
                  
                codigo = resultset.getString("CODIGO");  
                nome = resultset.getString("NOME");  
                salario = resultset.getString("SALARIO");
                modelo.addRow(new Object[] { codigo, nome, salario  } );
                  
            }  
        }  
            catch(Exception e)  
        {  
            JOptionPane.showMessageDialog(null,"Error "+e);  
        }  
  
        return modelo;  
    }

Na parte grafica vc xama o metodo pesquisa(modelo) , passando por parametro o modelo

espero ter ti ajudado ^^

ViniGodoy

Como diz o Entanglement, essa é a famosa “dica dos infernos”.

Primeiro, porque usa o DefaultTableModel;

Segundo, porque mistura a camada de view com o DAO. O model não deveria ser passado para o DAO.

Terceiro, porque novamente abandonou o uso do PreparedStatement;

Quarto, porque não trata adequadamente exceptions;

E quinto, último, mas não menos importante, porque mantém ResultSet, Statements e Connections abertas.
Criado 19 de outubro de 2010
Ultima resposta 21 de out. de 2010
Respostas 11
Participantes 5