Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

Melhor forma de acessar banco de dados e carregar em JTable

Eu desenvolvi um sistema, que realizava carregamento de dados em uma tabela muito rapidamente, utilizava um método em cada classe, como exemplo: String sql = "SELECT SERIAL_EQP AS código, NOMEFAN_CLI as Cliente, NOME_EQP AS nome, ID_EQP AS identificaçâo, " + "DIMENSAO_EQP AS dimensão, to_char(DATA_EQP, 'DD/MM/YYYY') AS data, REFERENCIA_EQP AS referência " + "FROM EQUIPAMENTO INNER JOIN CLIENTE ON CLIENTE_EQP = ID_CLI WHERE " + tipoPesq + " LIKE ?";

try { // Adiciona a pesquisa na tabela e define o tamanho das colunas ComandoDataBase pesquisa = new ComandoDataBase(); tabela.setModel(DbUtils.resultSetToTableModel(pesquisa.ConsultaPesquisa(sql, super.getPesquisa()))); tabela.getColumnModel().getColumn(0).setPreferredWidth(50); tabela.getColumnModel().getColumn(1).setPreferredWidth(170); tabela.getColumnModel().getColumn(2).setPreferredWidth(200); tabela.getColumnModel().getColumn(3).setPreferredWidth(180); tabela.getColumnModel().getColumn(4).setPreferredWidth(160); tabela.getColumnModel().getColumn(5).setPreferredWidth(100);

} catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); } Conforme fui evoluindo em java passei a criar meu próprio tableModel, e após o curso de java III e de collection do Alura passei a utilizar um List<> com o arraylist ( a ordem importa bastante ) para carregar esses dados e em seguida um foreach para carregar na tabela, e com as melhores praticas de OO criei um classe Equipamento, onde todas as consultas realizadas estão nessa classe, só que o sistema começou a apresentar um problema, a tabela passou a demorar bastante para carregar o que esta gerando um incomodo para quem utiliza o sistema, fica a duvida, qual a melhor maneira de carregar dados de um SGBD (postgresql) para uma tabela que utiliza tabelModel ?

segue me tablemodel public class AbstractTableModelEquipamento extends AbstractTableModel {

private static final long serialVersionUID = 1L; private List Dados; private String[] Colunas = new String[] { "Código", "Nome", "Identificação", "Dimensão", "Data", "Cliente", "Referência" }; private static final int Código = 0; private static final int Nome = 1; private static final int Identificação = 2; private static final int Dimensão = 3; private static final int Data = 4; private static final int Cliente = 5; private static final int Referência = 6;

// Construtor para o arraylist public AbstractTableModelEquipamento() { Dados = new ArrayList();

}

// Construtor para receber lista por parametro public AbstractTableModelEquipamento(List DadosLista) { Dados = new ArrayList(DadosLista); }

// Retorna o numero de colunas @Override public int getColumnCount() { return Colunas.length; }

// Retorna o numero de linhas e quantidade no array @Override public int getRowCount() { return Dados.size(); }

// Retorna o nome da coluna @Override public String getColumnName(int columnIndex) { return Colunas[columnIndex]; };

// Metodo que define o tipo de classe na coluna @Override public Class<?> getColumnClass(int columnIndex) { switch (columnIndex) { case Código: return String.class; case Nome: return String.class; case Identificação: return String.class; case Dimensão: return String.class; case Data: return String.class; case Cliente: return String.class; case Referência: return String.class; default: throw new IndexOutOfBoundsException("Coluna não localizada"); } }

// Metodo para editar ou não editar celulas @Override public boolean isCellEditable(int rowIndex, int columnIndex) { return false; }

// Retorna o conteudo da celula selecionada @Override public Object getValueAt(int rowIndex, int columnIndex) {

switch (columnIndex) { case 0: return Dados.get(rowIndex).getCodigo(); case 1: return Dados.get(rowIndex).getNome(); case 2: return Dados.get(rowIndex).getIdentificacao(); case 3: return Dados.get(rowIndex).getDimensao(); case 4: return Dados.get(rowIndex).getData(); case 5: return Dados.get(rowIndex).getNomeCliente(); case 6: return Dados.get(rowIndex).getReferencia(); } return null; }

// Faz a alteração dos valores na tabela e no array @Override public void setValueAt(Object aValue, int rowIndex, int columnIndex) { // Retorna o valor nulo if (aValue == null) return; // Entra nos casos switch (columnIndex) { case 0: Dados.get(rowIndex).setCodigo(Integer.parseInt((String) aValue));

case 1: Dados.get(rowIndex).setNome((String) aValue);

case 2: Dados.get(rowIndex).setIdentificacao((String) aValue);

case 3: Dados.get(rowIndex).setDimensao((String) aValue);

case 4: Dados.get(rowIndex).setData((String) aValue);

case 5: Dados.get(rowIndex).setNomeCliente((String) aValue);

case 6: Dados.get(rowIndex).setReferencia((String) aValue);

} // Atualiza this.fireTableRowsUpdated(rowIndex, rowIndex);

}

// Retorna a informação da classe referente a linha public Equipamento getComissao(int rowIndex) { return Dados.get(rowIndex); }

// Adiciona a classe especificando o modelo public void addLinha(Equipamento objeto) { // Adiciona Dados.add(objeto); // Ajusta o indice da coluna int lastIndex = getRowCount() - 1; // Atualiza a mudança fireTableRowsInserted(lastIndex, lastIndex);

}

// Remove a comissao da linha especificada public void removeLinha(int rowIndex) { // Remove Dados.remove(rowIndex); // Atualiza fireTableRowsDeleted(rowIndex, rowIndex); }

// Adiciona uma lista de dados no final da lista public void addListFull(List objeto) { // Registra o ultimo indice int indice = getRowCount(); // Adiciona os registros Dados.addAll(objeto); // Atualiza fireTableRowsInserted(indice, indice + Dados.size()); }

// Limpa a tabela public void limpar() { Dados.clear(); // Atualiza fireTableDataChanged(); }

}

2 respostas

opa, aqui na alura não temos cursos de swing.. existe uma chance média dessa sua dúvida durar um pouco aqui no fórum :(.

solução!

Bom, na verdade eu mesmo consegui resolver o problema no código, e o desempenho do sistema ficou fantástico que vou ate explicar aqui como resolvi. Realizei o curso de JDBC do Alura, que acabou resolvendo o problema, não tinha nada ver com a interface gráfica do swing e sim com a forma de acesso ao banco de dados.

Primeiro eu tinha uma classe Equipamento que estava misturada com o acesso a base de dados, sendo necessária a refatoração da classe em duas classes especificas Equipamento e EquipamentoDAO, a classe equipamento continha os atributos da tabela equipamento e a classe EquipamentoDAO tinha as formas de acesso ao banco de dados, isso resolveu parte do problema, a outra parte era que na tabela onde seriam exibidos os equipamentos, também seria exibido o cliente proprietário do equipamento, o que gerava um erro chamado de n+1, que é quando um query chama varias queryes dentro do seu loop, o que causava a demora para carregar o JTable.

public class Equipamento { private String nome, identificacao, dimensao, peso, ctrabalho, cteste, data, observacao, ncertificado, resultado, referencia; private String nomeCliente; private int codigo, validade, codCliente, codOrcamento; private boolean status, faturado; // getters e setters }

public class EquipamentoDAO { private final Connection con; public EquipamentoDAO(Connection con) { this.con = con; } // Metodo para buscar uma lista de equipamento public List buscarListaDeEquipamentos() { List lista = new ArrayList<>(); String sql = "SELECT SERIAL_EQP, NOME_EQP, ID_EQP, DIMENSAO_EQP, PESO_EQP, CTRABALHO_EQP, CTESTE_EQP, " + "to_char(DATA_EQP,'DD/MM/YYYY'), OBSERVACAO_EQP, NCERTIFICADO_EQP, VALIDADE_EQP, RESULTADO_EQP, " + "STATUS_EQP, REFERENCIA_EQP, CLIENTE_EQP, ORCAMENTO_EQP, FATURADO_EQP, NOMEFAN_CLI FROM EQUIPAMENTO " + "JOIN CLIENTE ON ID_CLI = CLIENTE_EQP ORDER BY SERIAL_EQP";

try (PreparedStatement stmt = con.prepareStatement(sql)) { stmt.execute(); transformaSaidaEmLista(lista, stmt); } catch (SQLException e) { new SQLException("Não foi possível realizar essa operação no banco de dados"); } return lista; } // Tranforma a ResultSet em um arraylist private void transformaSaidaEmLista(List lista, PreparedStatement stmt) throws SQLException { try (ResultSet rst = stmt.getResultSet()) { while (rst.next()) { Equipamento equipamento = new Equipamento(); equipamento.setCodigo(rst.getInt(1)); equipamento.setNome(rst.getString(2)); equipamento.setIdentificacao(rst.getString(3)); equipamento.setDimensao(rst.getString(4)); equipamento.setPeso(rst.getString(5)); equipamento.setCtrabalho(rst.getString(6)); equipamento.setCteste(rst.getString(7)); equipamento.setData(rst.getString(8)); equipamento.setObservacao(rst.getString(9)); equipamento.setNcertificado(rst.getString(10)); equipamento.setValidade(rst.getInt(11)); equipamento.setResultado(rst.getString(12)); equipamento.setStatus(rst.getBoolean(13)); equipamento.setReferencia(rst.getString(14)); equipamento.setCodCliente(rst.getInt(15)); equipamento.setCodOrcamento(rst.getInt(16)); equipamento.setFaturado(rst.getBoolean(17)); equipamento.setNomeCliente(rst.getString(18)); lista.add(equipamento); } } } }

Dessa forma o acesso ficou moleza // Carrega as insformações para a tabela @Override protected void carregarTabela() { this.TabelaModel.limpar(); EquipamentoDAO ConsultaEquipamentos = new EquipamentoDAO(new ConexaoFactory().getConnection()); List listaEquipamento = ConsultaEquipamentos.buscarListaDeEquipamentos();

for (Equipamento equipamento : listaEquipamento) { this.TabelaModel.addLinha(equipamento); AjustarColunasTabela(); } }

O carregamento ficou muito rápido apesar de o banco de dados possuir mais de 2 mil registros...

Quer mergulhar em tecnologia e aprendizagem?

Receba a newsletter que o nosso CEO escreve pessoalmente, com insights do mercado de trabalho, ciência e desenvolvimento de software