Como reabrir um ResultSet

13 respostas
ezem.rs

Olá Pessoal,

Tenho uma dúvida quanto ao ResultSet.

No caso abaixo grava somente na primeira vez pois na segunda vez loop do FOR, da mensagem de erro " java.sql.SQLException: Operation not allowed after ResultSet closed"

dtm_recupera_tabela= p_ManterPF_Aba21.recuperaTabela(); // Recupera a tabela da Aba 2 for (int i=0;i<dtm_recupera_tabela.getRowCount();i++){ int resp2 = st.executeUpdate("INSERT INTO TB_PATRIMONIO_PF (TB_PESSOAS_FISICAS_ID_PF,TB_TIPO_PATRIMONIO_ID_TIPO_PATRIMONIO,DESC_COMPLEMENTO,VALOR_PATRI) values ('"+SQL1.getInt(1)+"','"+dtm_recupera_tabela.getValueAt(i, 0)+"','"+dtm_recupera_tabela.getValueAt(i, 1)+"','"+1+"')"); }

Lembrando que se eu eu tiver somente um registro a gravar, grava normalmente. O problema é quando tem mais que um registro a ser gravado, ou seja, cada volta do loop do FOR teria que gravar uma linha do banco, mas na segunda volta apresenta o erro.

Pelo que pesquisei isso ocorre por que o após passar pelo st.executeUpdate, ele fecha o ResultSet, portanto na segunda vez encontra o ResultSet Fechado.

Como eu faço para reabrir o ResultSet?

Obs: Meu construtor esta assim definido:

public F_Manter_PF() { initComponents(); configuraBotoes_pesquisar(); try { st = new Conexao_DB().getConnection(); } catch (SQLException ex) { System.out.println("Erro conexao"+ ex.toString()); } }

Desde de já Obrigado.

13 Respostas

tondatto

Utilize um objeto PreparedStatement.

PreparedStatement ps = null
String insertStr = "INSERT INTO TB_PATRIMONIO_PF ("
          + "TB_PESSOAS_FISICAS_ID_PF "
          + ",TB_TIPO_PATRIMONIO_ID_TIPO_PATRIMONIO "
          + ",DESC_COMPLEMENTO "
          + ",VALOR_PATRI) "
          + "values (?, ?, ?,'1')";

try{
    connection.setAutoCommit(false);
    ps = connection.prepareStatement(insertStr);

    for (int i=0;i<dtm_recupera_tabela.getRowCount();i++){ 
        ps.setInt(1, SQL1.getInt(1));    // configura parâmetro 1
        ps.setString(2, dtm_recupera_tabela.getValueAt(i, 0));     // configura parâmetro 2 - String?
        ps.setString(3, dtm_recupera_tabela.getValueAt(i, 1));     // configura parâmetro 3 - String?
        ps.executeUpdate();      // executa insert
    }
} catch (SQLException e {
    e.printStackTrace();
} finally {
    ps.close();
    connection.setAutoCommit(true);
}
ezem.rs

Olá,

Desde já obrigado.

Porém tenho uma duvida de como fazer a conexão com o banco. Até então eu tinha definido no meu construtor a conexão como segue. Em anexo o erro.

public F_Manter_PF() { initComponents(); configuraBotoes_pesquisar(); try { st = new Conexao_DB().getConnection(); } catch (SQLException ex) { System.out.println("Erro conexao"+ ex.toString()); } }

Na minha classe de conexão eu tenho esse codigo:

package projeto_cobra;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

public class Conexao_DB {
     private static final String URL = "jdbc:mysql://localhost/linsz_db";
     private static final String DRIVER = "com.mysql.jdbc.Driver";
     private static final String USUARIO = "root";
     private static final String SENHA = "3477";
    
  public Statement getConnection() throws SQLException {
        try {
            Class.forName(DRIVER);
            Connection conn = DriverManager.getConnection(URL,USUARIO,SENHA);
            return conn.createStatement();       
        } catch (ClassNotFoundException e) {
            throw new SQLException (e.getMessage());
        
        }
  }
}

Se puderes, me ajuda em mais essa.
Obrigado.


tondatto

Amigo, sugiro você fazer o seguinte:

1) Altere o método getConnection() da classe Conexao_DB para retornar o objeto Connection. Assim você tem mais liberdade em preparar os statements.
public Connection getConnection() throws SQLException {  
    try {  
        Class.forName(DRIVER);  
        Connection conn = DriverManager.getConnection(URL,USUARIO,SENHA);  
        return conn; 
    } catch (ClassNotFoundException e) {  
        throw new SQLException (e.getMessage());   
}
2) Na classe F_Manter_PF, crie uma propriedade Connection connection e trabalhe com este objeto quando for fazer tanto uma pesquisa, quanto uma inserção.
public class F_Manter_PF {
    ...
    Connection connection;

    public F_Manter_PF() {  
        initComponents();  
        configuraBotoes_pesquisar();  
        try {  
            connection = new Conexao_DB().getConnection();  
        } catch (SQLException ex) {  
            System.out.println("Erro conexao"+ ex.toString());  
        }        
    } 
...
}
Acredito que seja só isso. Você tendo o objeto da conexão com o banco (Connection), você pode criar vários tipos de Statements e montar diferentes estratégias de consulta SQL.
kinrpg

Opa esse post foi bem instrutivo. Eu tenho uma duvida.
Eu crio o Connection que pode ser compartilhado com várias classes. Mas cada classe tem seus próprios Statements.

No caso la no Banco de Dados isso criaria uma unica conexão independente do numero de ResultSet e Statements, ou pra cada Statements ou ResultSet que eu uso cria-se uma nova conexão no Banco de dados?

tondatto

Salvo engano, como toda vez que você chama o método getConnection() ele carrega o driver de conexão, é criada uma nova conexão.
Para sempre usar a mesma conexão, acredito que você deveria criar uma propriedade static Connection na classe Conexao_DB.

kinrpg

tondatto:
Salvo engano, como toda vez que você chama o método getConnection() ele carrega o driver de conexão, é criada uma nova conexão.
Para sempre usar a mesma conexão, acredito que você deveria criar uma propriedade static Connection na classe Conexao_DB.

Opa… Então eu posso usar o mesmo conection pra varios Statements e ResultSet assim :3? Valeu o esclarecimento eu estava com esta duvida a tempo… Vou testar.

Ruttmann

Uma alternativa aos uso de static é transformar a classe de conexão em um singleton, e compartilhar essa conexão por parâmetro entre todas as classes que precisarem utilizá-la…

:roll:

kinrpg
Ruttmann:
Uma alternativa aos uso de static é transformar a classe de conexão em um singleton, e compartilhar essa conexão por parâmetro entre todas as classes que precisarem utilizá-la...

:roll:

No caso eu tenho uma conexão estática chamada ConnectionFactory.getConnection().

Estou fazendo da seguinte maneira para ver se ele compartilha a mesma conexão no processo:

public class ListagemSelect {

    private Connection con;
    public ListagemSelect(Connection con) {
        if (con != null) {
            this.con = con;
        } else {
            this.con = ConnectionFactory.getConnection();
        }
    }

    public List GeraLista() {
        //Listagem das Tabelas
        List<Listagem> lista = new ArrayList<Listagem>();
        Listagem tabelas = new Listagem();   

        try {
            Clientes cli = new Clientes(con);
            tabelas.setClientes(cli.ListaClientes());

            Pedidos ped = new Pedidos(con);
            tabelas.setPedido_S(ped.ListaPedidos());
        } finally {
            ConnectionFactory.closeConnection(con);
        }

        lista.add(tabelas);
        return lista;
    }
}

Ou Seja se eu chamo essa classe e não passo pra ela uma conexão que ja criei ela cria uma, e passa essa conexão para as demais classes que ela utiliza para alimentar sua lista. Nesse caso (que é como estou fazendo aqui) ela ainda usa a mesma conexão ou cada vez que chamo uma classes ela cria uma conexão nova apenas copiando as configurações de Con?

Ruttmann
kinrpg:
Ruttmann:
Uma alternativa aos uso de static é transformar a classe de conexão em um singleton, e compartilhar essa conexão por parâmetro entre todas as classes que precisarem utilizá-la...

:roll:

No caso eu tenho uma conexão estática chamada ConnectionFactory.getConnection().

Estou fazendo da seguinte maneira para ver se ele compartilha a mesma conexão no processo:

public class ListagemSelect {

    private Connection con;
    public ListagemSelect(Connection con) {
        if (con != null) {
            this.con = con;
        } else {
            this.con = ConnectionFactory.getConnection();
        }
    }

    public List GeraLista() {
        //Listagem das Tabelas
        List<Listagem> lista = new ArrayList<Listagem>();
        Listagem tabelas = new Listagem();   

        try {
            Clientes cli = new Clientes(con);
            tabelas.setClientes(cli.ListaClientes());

            Pedidos ped = new Pedidos(con);
            tabelas.setPedido_S(ped.ListaPedidos());
        } finally {
            ConnectionFactory.closeConnection(con);
        }

        lista.add(tabelas);
        return lista;
    }
}

Ou Seja se eu chamo essa classe e não passo pra ela uma conexão que ja criei ela cria uma, e passa essa conexão para as demais classes que ela utiliza para alimentar sua lista. Nesse caso (que é como estou fazendo aqui) ela ainda usa a mesma conexão ou cada vez que chamo uma classes ela cria uma conexão nova apenas copiando as configurações de Con?

Isso mesmo, bem assim que eu fazia também...

Se você já tiver uma conexão ativa ela é usada, caso contrário, será criada uma nova conexão...

Eu acho essa uma prática boa, para projetos de pequeno porte funciona muito bem. Não posso te confirmar muito isso pois sou iniciante na área. Mas como exemplo te deixo um trabalho que fiz num curso umas semanas atrás...

Projetamos(era em grupo) uma agenda de compromissos pessoais e financeiros, onde a tela principal era um calendário. O título de cada compromisso aparecia no dia referido no calendário. Usamos hibernate para a persistência, e por conta do uso do framework testamos exaustivamente a aplicação pra ver se não ocorria perda de performance.

Outras equipes fizeram projetos que demoravam demais pra atualizar um simples SELECT no banco, sem usar nenhum framework de persistência. Nosso projeto atualizava instantâneamente um mês com 10 compromissos em cada dia, puxando isso tudo do banco de dados.

Uma coisa que contribuiu muito para a performance com o banco foi o uso de um singleton para a conexão, onde criamos somente uma conexão pra efetuar todas as operações de persistência...

kinrpg

=D Legal… Acertei alguma coisa AHSUAHUS

Agora eu preciso aprender a trabalhar com persistencia, uma vez que este dados esta retornando de um Select simples (ResultSet rs = con.getStatment.executeQuery(“select * from tabela”)). Valeu o exemplo, estou já modificando umas coisas nas minhas classes aqui :3

kinrpg

Teve um ganho em velocidade bastante representativo usando o procedimento acima. No entanto no SQLServer quando eu vejo o numero de conexões no momento que ele esta lendo as tabelas ele demonstra 23 conexões.

Assim que acaba o procedimento um único close fecha todas as conexões.

Ruttmann

kinrpg:
Teve um ganho em velocidade bastante representativo usando o procedimento acima. No entanto no SQLServer quando eu vejo o numero de conexões no momento que ele esta lendo as tabelas ele demonstra 23 conexões.

Assim que acaba o procedimento um único close fecha todas as conexões.

Você está usando o banco direto na sua máquina?

E ele faz 23 conexões?

:-o

Teria que analisar melhor isso aí…

kinrpg

Ruttmann:
kinrpg:
Teve um ganho em velocidade bastante representativo usando o procedimento acima. No entanto no SQLServer quando eu vejo o numero de conexões no momento que ele esta lendo as tabelas ele demonstra 23 conexões.

Assim que acaba o procedimento um único close fecha todas as conexões.

Você está usando o banco direto na sua máquina?

E ele faz 23 conexões?

:-o

Teria que analisar melhor isso aí…

Na verdade Cliente Requisita XML feita com dados do DB -> Aplicativo War -> Glassifish -> Recurso de Pool -> SQL Server

=/

Edit: Depois que escrevi a frase acima, fui pesquisar pedaço por pedaço do meu webservice, estava tudo OK com o XML, Tudo certo com as classes, sem problema no War, tudo OK com o Glassfish (Deploy? Não sei o nome) e no Recurso de Pool :-o … Tinha uns números altos em Tamanho Inicial e Mínimo do Pool, Tamanho Máximo do Pool e Qtde. Redimens. Pool. Mudei estes números e tudo ficou como deve ser :3

Criado 7 de setembro de 2012
Ultima resposta 11 de set. de 2012
Respostas 13
Participantes 4