Dúvida "teórica" resultset

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 ???

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.

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

Estou achando essa parte meio complexa.

[code]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;
}[/code]

e na gráfica

[code]fb = new formBanco();

fb.OpenDB();
    
DefaultTableModel modelo = (DefaultTableModel) tabela.getModel();

fb.pesquisa();

modelo.addRow(new Object [] {fb.retorna1(),fb.retorna2(),fb.retorna3()});

[/code]

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

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

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

[code] while(resultset.next())
{
conseguiu = true;

            codigo = resultset.getString("CODIGO");  
            nome = resultset.getString("NOME");  
            salario = resultset.getString("SALARIO");  
        } [/code]

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!

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:

[code]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);[/code]

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!

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

[code]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; }
}[/code]

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).

  1. 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:

[code]public List 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;
} [/code]

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.

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!

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:

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!

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 ^^

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.