Cadastro Insert Into

24 respostas
charleston10

Estou com um problema, quando eu vou cadastrar dados de uma tabela à outra, acontece um erro dizendo que o ResultSet esta fechado,
tentei várias métodos para consertar, todos sem êxito.

Tenho uma tabela com alguns cadastro.
Preciso pegar todos os dados dessa tabela e passar para outra. (É um tabela temporária)
Após isso eu deleto todos os registros dessa tabela temporária.

public void Metodo(){ 

       Banco.sSQL = "SELECT * FROM TABELA_TEMP";

       try{
             
             Statement sta = Banco.cnn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
             ResultSet res = sta.executeQuery(Banco.sSQL);
            

             //Pega todos registros adicionados na lista
             while (res.next()){

                 int CodigoVenda = res.getInt("CODIGO_VENDA");
                 int CodigoProduto = res.getInt("CODIGO_PRODUTO");
                 String Descricao = res.getString("DESCRICAO");
                 float Valor = res.getFloat("VALOR");
                 int Qtde = res.getInt("QTDE");
                 float Total = res.getFloat("TOTAL");

                 try{
                        String sSQLCadastro = "INSERT INTO PRODUTOS_VENDIDOS(CODIGO_VENDA,CODIGO_PRODUTO,DESCRICAO,"
                            + "VALOR,QTDE,TOTAL) "
                            + "VALUES(?,?,?,?,?,?)";

                        PreparedStatement pst = Banco.cnn.prepareStatement(sSQLCadastro);

                        pst.setInt(1, CodigoVenda );
                        pst.setInt(2, CodigoProduto);
                        pst.setString(3, Descricao);
                        pst.setFloat(4,Valor);
                        pst.setInt(5, Qtde);
                        pst.setFloat(6, Total);
                        pst.execute();
                      
                 }catch(Exception erro){
                     JOptionPane.showMessageDialog(null, "Erro ao inserir registro a tabela " + erro);
                 }
                
                //Mensagem de teste para verificar se foi cadastrado;
                JOptionPane.showMessageDialog(null,"GRAVADO: " + CodigoProduto);

             }             

         }catch(Exception erro){
                JOptionPane.showMessageDialog(null, "Erro gravar produtos listados\n\n " + erro);
         }
    }

Pego os registros adicionados duma lista através do While um por um, depois que pego eu gravo esse registro em outra tabela,
depois volta no While fazendo a mesma repetição até terminar os registros.

Alguem sabe o problema?

O erro acontece aki

}catch(Exception erro){
                JOptionPane.showMessageDialog(null, "Erro gravar produtos listados\n\n " + erro);
         }

Mensagem

[color=red]Erro gravar produtos listados
org.firebirdsql.jdbc.FBSQLException: The result set is closed[/color]

24 Respostas

BrunoFurtado

Cara, não sei qual é a pira da situação, mas o bagulho tá meio compuso ai…

Inicialmente eu criaria uma classe Bean contendo atributos os valores presentes na tabela temporária…
Feito isso, eu utilizaria seu “Metodo()” para adicionar os valores presentes na tabela temporária dentro de um objeto desta Bean.
Por fim, criaria um novo método com a função única de inserir os dados desta Bean populada em outro local do banco de dados.

O erro deve estar ocorrendo pois vc não está finalizando sua conexão, prepared statement e result set.
Não esqueça de utilizar o finally para fechar a conexão com o banco de dados, isto futuramente pode vir a dar problemas graves.

Espero ter ajudado.

F

Coloque isso no catch pra ver se da um erro mais específico:

JOptionPane.showMessageDialog(null,erro.getMessage());
charleston10

BrunoFurtado

O problema que eu vi não este, eu abro o banco de dados no inicio da aplicação e fecho quando encerro o mesmo;
E tambem fecho o resultset qndo termina de executar um metodo.

felipevs

O erro especifico é este:

org.firebirdsql.jdbc.FBSQLException: The result set is closed


Quando eu mudo o While(rs.next()) para if(res.next()) - ele cadastra normalmente, porém somente um registro, eu uso o While para pegar todos os registro,
ja que o if pega o primeiro registro encontrado somente;

Mas com o while nao funciona, tentei usar um for, porém acontece o mesmo erro…

:?

discorpio

Boa tarde a todos.

Tente isso:

// Mude esta sintaxe:
   pst.execute();  

   // Por esta:
   pst.executeUpdate();

A Classe PreparedStatement possui dois métodos além do método execute(), que são: “executeQuery()” para selecionar (SELECT) registros dentro da tabela, apanhando-os, e o “executeUpdate()” que atualiza a tabela (INSERT, UPDATE ou DELETE), e talvez seja esse o motivo porque não está funcionando.

Outra coisa que eu gostaria de saber, qual é essa sua lógica de criar uma tabela temporária no Banco de Dados :?: :?: :?:

Creio eu que voce está criando recursos desnecessários, pois não seria mais lógico registrar o dado diretamente na tabela definitiva, pois além de criar extensos códigos para serem interpretados pela aplicação, desenvolve extenso trabalho de processamento no banco, imagine você ter que transferir 500.000 registros de uma tabela temporária para uma definitiva, para depois apagar os 500.000 registros da tabela temporária :?: :?: :?: Já pensou no assunto.

Se você pretende só registrar pedidos de vendas que foram concretizados pelos clientes, então registre tudo numa tabela só, e crie um campo com um dado booleano, dizendo se o pedido foi vendido ou não.

Além disso, voce vai deletar os dados cujos pedidos não foram concretizados no dia :?: :?: :?: E se dois meses depois o cliente queira retificar um pedido que fora feito dois meses antes, porém não se lembra dos detalhes do pedido, a vendedor ficaria então de calça justa, não ficaria :?: :?: :?:

Fica muito mais prático e mais enxuto, mais seguro, onde a aplicação fica bem menor de se interpretar, mais rápido e a acesso a banco fica com a performance mais rápida também.

Um abraço.

charleston10

discorpio

Mudei a sintaxe, mas o mesmo erro ocorre;

A tabela temporária é usada em meu projeto para guardar dados de um terminal de vendas;
É melhor eu usar assim, para eu poder manipular com liberdade os dados, sem que ocorra erro de interferência.

Recursos de uma tabela temporária:

Posso manipular os dados inserindo um registro, o cliente compra um produto, então é inserido à essa tabela;

alterando registro, o cliente esqueceu de pegar mais um produto q ja tem adiciona na lista de vendas, então eu só edito a qtde para + 1, sem precisar gravar o mesmo registro;

excluindo registro, o cliente pega varias produtos, mas o subtotal deu a mais e ele quer retirar alguns produtos da lista de vendas, então eu deleto da tabela;

Um grande problema que ocorre tambem sem a tabela temporária, é varios terminais rodando ao mesmo tempo, caso um vendedor inclui um produto na lista e outro vendedor faz o mesmo, porém tudo ao mesmo tempo, pode ocorrer interferencia ao registrar; pode registrar com o mesmo codigo, ou informações alteradas, com a tabela temporária é impossível isso acontecer, pois a tabela é responsavel somente pelo seu terminal.

O mais importante, de-repente o computador desliga por causa de um raio ou qlqr outra coisa, e ai como fazemos? temos que passar todos os produtos novamente, e assim repetir todo o procedimento?

Não, com a tabela temporária, os registros não são apagados, e então eu posso continuar a venda que estava em andamento;

No final da venda, eu encerro a venda, mas os dados da tabela temporária, só vai servir para guardar os dados do produto e o codigo da venda;
assim quando terminada a venda, eu pego esses dados e adiciono um uma tabela que guarda todos os produtos vendidos; pronto! -

BrunoFurtado

Brother,
Fiquei intrigado e resolvi fazer um pequeno teste.
Utilizando MySQL5, driver JDBC e JDK6 deu tudo certo.

Talvez o Firebird ou seu driver finalize o ResultSet em alguma parte do processo.

Outro fator é que é utilizado um Statement, depois um PreparedStatement…
A utilização de um único PreparedStatement me parece agilizar, utilizar menos memória de servidor e realizar apenas 1 conexões com o banco de dados.

Enfim, este teu código tá meio nebuloso…

De qualquer forma, axo essa lógica meio arriscada…
E se ocorre alguma falha durante a execução deste método? A tabela temporária é apaga e os dados não são copiados?
Desativar o auto comit é uma solução, mas enfim, ainda existirão problemas…

Eu copiaria linha a linha, com auto comit desligado, fechando a conexão sempre…
É mais lento, mas acredito que seja a forma correta.

De qualquer forma, fiz um teste do teu jeito e deu certo.
Tente utilizar esse código pra ver oq rola…

package dbconn;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import dbconn.persistence.MysqlDaoFactory;

public class DBConnMain {

	public static void main(String[] args) {
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		String sql = null;
		
		System.out.println("Estabelecendo conexao com base de dados...");
		
		try {
			conn = MysqlDaoFactory.createConnection();
		} catch (Exception e) {
			System.out.println("Falha ao conectar com MySQL 5");
			//e.printStackTrace();
		}
		
		System.out.println("Conexao estabelecida com sucesso!");
		
		sql = "SELECT * FROM TABELA_TEMP";
		
		try {
			System.out.println("\nExecutando query na base de dados...");
			
			pstmt = conn.prepareStatement(sql);
			rs = pstmt.executeQuery();
			
			System.out.println("Query executada com sucesso.");
			System.out.println("\nIniciando insercao de dados na tabela final....");
			
			while (rs.next()) {
				sql = "INSERT INTO ";
				sql += "PRODUTOS_VENDIDOS(CODIGO_VENDA,CODIGO_PRODUTO,DESCRICAO, VALOR,QTDE,TOTAL) ";
				sql += "VALUES(?,?,?,?,?,?)";
				
				pstmt = conn.prepareStatement(sql);
				pstmt.setInt(1, rs.getInt("CODIGO_PRODUTO"));
				pstmt.setInt(2, rs.getInt("CODIGO_VENDA"));
				pstmt.setString(3, rs.getString("DESCRICAO"));
				pstmt.setFloat(4, rs.getFloat("VALOR"));
				pstmt.setInt(5, rs.getInt("QTDE"));
				pstmt.setFloat(6, rs.getFloat("TOTAL"));
				
				System.out.println("Codigo de produto inserido: " + rs.getInt("CODIGO_PRODUTO"));
				
				pstmt.execute();
			}
			
			System.out.println("Insercao em tabela final realizada com sucesso.");
		} catch (SQLException e) {
			System.out.println("Falha ao tentar copiar dados da tabela temporaria para final.");
			//e.printStackTrace();
		} finally {
			close(conn, pstmt, rs);
		}
		
		System.out.println("\nConexoes e aplicacao finalizada.");
	}
	
	private static void close(Connection connection, PreparedStatement preparedStatement, ResultSet resultSet) {
		try {
			if (resultSet != null)
				resultSet.close();
			
			if (preparedStatement != null)
				preparedStatement.close();
				
			if (connection != null)
				connection.close();
		} catch (SQLException e) {
			System.out.println("Falha ao tentar finalizar conexoes relacionadas a base de dados.");
			//e.printStackTrace();
		}
	}

}
ribclauport

Opa também testei aqui e deu certo, será que o amigo poderia postar o codigo que “pega a conexão” para a gente analisar.

package conexao;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

import javax.swing.JOptionPane;


public class TesteBD {
	public static void main(String[] args) throws SQLException {
		metodo();
		
	}
	public static Connection connection() {
		Connection con = null;
		try {
			Class.forName("com.mysql.jdbc.Driver");
		} catch (ClassNotFoundException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}

		// String url = "jdbc:mysql://localhost/jdbc?user=root&password=12345";
		String url = "jdbc:mysql://localhost:3306/titan";

		Properties prop = new Properties();
		prop.setProperty("user", "root");
		prop.setProperty("password", "root");

		try {
			// Connection con = DriverManager.getConnection(url);
			con = DriverManager.getConnection(url, prop);

		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return con;

	}

	public static void metodo() throws SQLException {
		String sSQL = "SELECT * FROM produtos_vendidos";
		Connection con = connection();
		Statement sta = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
		ResultSet res = sta.executeQuery(sSQL);
		
		try {
			

			// Pega todos registros adicionados na lista
			while (res.next()) {

				int CodigoVenda = res.getInt("CODIGO_VENDA");
				int CodigoProduto = res.getInt("CODIGO_PRODUTO");
				String Descricao = res.getString("DESCRICAO");
				float Valor = res.getFloat("VALOR");
				int Qtde = res.getInt("QTDE");
				float Total = res.getFloat("TOTAL");
				
				System.out.println(CodigoVenda);
				
				try {
					String sSQLCadastro = "INSERT INTO PRODUTOS_VENDIDOS_CRIACAO(CODIGO_VENDA,CODIGO_PRODUTO,DESCRICAO,"
							+ "VALOR,QTDE,TOTAL) " + "VALUES(?,?,?,?,?,?)";

					//PreparedStatement pst = con.prepareStatement(sSQLCadastro);
					PreparedStatement pst = con.prepareStatement(sSQLCadastro);

					pst.setInt(1, CodigoVenda);
					pst.setInt(2, CodigoProduto);
					pst.setString(3, Descricao);
					pst.setFloat(4, Valor);
					pst.setInt(5, Qtde);
					pst.setFloat(6, Total);
					pst.execute();

				} catch (Exception erro) {
					JOptionPane.showMessageDialog(null,
							"Erro ao inserir registro a tabela " + erro);
				}
			}

		} catch (Exception erro) {
			JOptionPane.showMessageDialog(null,
					"Erro gravar produtos listados\n\n " + erro);
		}finally{
			if(res!=null&&!res.isClosed()){
				res.close();
			}
			if(sta!=null&&!sta.isClosed()){
				sta.close();
			}
			if(con!=null){
				if(!con.isClosed()){
					con.close();
				}
			}
		}
		
	}
}




BrunoFurtado

Opa,

Segue DaoFactory simplificada.
Não criei interface e o tdo mais, pq iria dar mto trabalho…

package dbconn.persistence;

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

public class MysqlDaoFactory {

	private static final String JDBC_DRIVER = "org.gjt.mm.mysql.Driver";
	private static final String URL_CONNECTION = "jdbc:mysql://servidor:3306/TESTES";
	private static final String DB_USER = "usuario";
	private static final String DB_PASS = "senha";
	
	public static Connection createConnection() throws ClassNotFoundException, SQLException {
		Class.forName(JDBC_DRIVER);
		return DriverManager.getConnection(URL_CONNECTION, DB_USER, DB_PASS);
	}
		
}
discorpio

Boa tarde a todos.

Você já ouviu falar de “Transação” e “Persistência de dados”.

Repare o que nosso amigo Bruno Furtado disse:

Quando voce realiza uma instrução sql, os dados não são enviados diretamente para o Servidor remoto, mas sim atualiza o ResultSet que está na máquina cliente, e os dados só serão enviados a servidor com uma instrução Commit.

O que realmente está acontecendo com a sua aplicação que a sua conexão com o seu banco de dados está com o AutoCommit setado para true, e isto significa dizer que a cada instrução SQL, seja de seleção (Insert) ou de atualização (Insert, Update ou Delete),logo após é realizado um Commit, ou seja, os dados são enviados a banco e depois a conexão com o banco é fechada, este procedimento é assim determinado, porque visa exatamente a segurança dos dados no banco, tendo em vista as intemperes que por ventura ocorre e que voce próprio citou em seu último post.

“Charleston10”:

O mais importante, de-repente o computador desliga por causa de um raio ou qlqr outra coisa, e ai como fazemos? temos que passar todos os produtos novamente, e assim repetir todo o procedimento?

Para poder te explicar melhor, vamos ver passo a passo, todo o procedimento de acesso a banco de dados em servidor remoto.

1º) Em caso de atualização (Insert, Update ou Delete), a conexão se estabelece e o SGDB cria o ResultSet de acordo com o critério da seleção.

2º) Uma transação é aberta para enviar o ResultSet atualizado ao Servidor. Este ResultSet já configura uma persistência de dados no cache de memória do computador cliente.

3º) Se porventura o AutoCommit estiver “true”, a conexão é fechada juntamente com o ResultSet, e é por isso que alguns desenvolvedores criam uma persistência de dados particular porém isto no HD do computador Cliente e não no banco, você está criando a tabela temporária no banco, o que não é correto, pois de que adianta se as intemperes citadas por você ocorrem no momento em que o terminal de vendas está atualizando a tabela temporária no banco. :?: :?: :?:

No caso de consulta seleção (Select), não há Commit, pois o mesmo só é realizado para atualização do banco, entretanto após aberta a conexão, uma transação é aberta para enviar o ResultSet montado no servidor com os dados do critério selecionado pela instrução Select, a transação é fechada imediatamente após o carregamento do ResultSet no cliente é fecha a conexão em caso de autocommit = true.

Se o AutoCommit estiver setado para false, somente a transação é fechada após uma instrução SQL ser completada, porém a conexão com o banco permanece aberta desde o momento que voce a inicia, ou seja, invoca o método de conexão.

A invés de voce trabalhar com tabelas temporárias, ou até mesma criar persistência de dados em HD, o correto é trabalhar com o que chamamos de registros desconectados, ou seja, voce abrir a conexão juntamente com a transação, somente para apanhar ou enviar dados ao servidor, e fechar ambas imediatamente tão logo a instrução acaba de ser executada, e a melhor maneira de se fazer isto, seria utilizar um pool de conexão, e isto o Apache Tomcat faz muito bem, ao invés de uma conexão direta, pois garante mais segurança ao servidor. Veja este post no link abaix:

Um abraço.

ribclauport

Realmente a explicação foi fantástica a respeito de como funciona o banco,
porém veja bem, eu setei na mão a coisa para commit true, como pode ser observado no código,
e continuou funcionando, discorpio, por favor poderia então me explicar por que está funcionando meu
código e não a do amigo que fez o post?

Creio que a classe de conexão do amigo que efetuou o post deveria ser analisada, ficariamos muito felizes se ele colocasse
a classe de conexão, por que acho que lá é que esta o problema.

Segue o código com auto commit true e mesmo assim funcionando.

package conexao;  
      
    import java.sql.Connection;  
    import java.sql.DriverManager;  
    import java.sql.PreparedStatement;  
    import java.sql.ResultSet;  
    import java.sql.SQLException;  
    import java.sql.Statement;  
    import java.util.Properties;  
      
    import javax.swing.JOptionPane;  
      
      
    public class TesteBD {  
        public static void main(String[] args) throws SQLException {  
            metodo();  
              
        }  
        public static Connection connection() {  
            Connection con = null;  
            try {  
                Class.forName("com.mysql.jdbc.Driver");  
            } catch (ClassNotFoundException e1) {  
                // TODO Auto-generated catch block  
                e1.printStackTrace();  
            }  
      
            // String url = "jdbc:mysql://localhost/jdbc?user=root&password=12345";  
            String url = "jdbc:mysql://localhost:3306/titan";  
      
            Properties prop = new Properties();  
            prop.setProperty("user", "root");  
            prop.setProperty("password", "root");  
      
            try {  
                // Connection con = DriverManager.getConnection(url);  
                con = DriverManager.getConnection(url, prop);  
      
            } catch (SQLException e) {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
            }  
            return con;  
      
        }  
      
        public static void metodo() throws SQLException {  
            String sSQL = "SELECT * FROM produtos_vendidos";  
            Connection con = connection();  
            Statement sta = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);  
            ResultSet res = sta.executeQuery(sSQL); 
           [color=red] con.setAutoCommit(true)[/color]
              
            try {  
                  
      
                // Pega todos registros adicionados na lista  
                while (res.next()) {  
      
                    int CodigoVenda = res.getInt("CODIGO_VENDA");  
                    int CodigoProduto = res.getInt("CODIGO_PRODUTO");  
                    String Descricao = res.getString("DESCRICAO");  
                    float Valor = res.getFloat("VALOR");  
                    int Qtde = res.getInt("QTDE");  
                    float Total = res.getFloat("TOTAL");  
                      
                    System.out.println(CodigoVenda);  
                      
                    try {  
                        String sSQLCadastro = "INSERT INTO PRODUTOS_VENDIDOS_CRIACAO(CODIGO_VENDA,CODIGO_PRODUTO,DESCRICAO,"  
                                + "VALOR,QTDE,TOTAL) " + "VALUES(?,?,?,?,?,?)";  
      
                        //PreparedStatement pst = con.prepareStatement(sSQLCadastro);  
                        PreparedStatement pst = con.prepareStatement(sSQLCadastro);  
      
                        pst.setInt(1, CodigoVenda);  
                        pst.setInt(2, CodigoProduto);  
                        pst.setString(3, Descricao);  
                        pst.setFloat(4, Valor);  
                        pst.setInt(5, Qtde);  
                        pst.setFloat(6, Total);  
                        pst.execute();  
      
                    } catch (Exception erro) {  
                        JOptionPane.showMessageDialog(null,  
                                "Erro ao inserir registro a tabela " + erro);  
                    }  
                }  
      
            } catch (Exception erro) {  
                JOptionPane.showMessageDialog(null,  
                        "Erro gravar produtos listados\n\n " + erro);  
            }finally{  
                if(res!=null&&!res.isClosed()){  
                    res.close();  
                }  
                if(sta!=null&&!sta.isClosed()){  
                    sta.close();  
                }  
                if(con!=null){  
                    if(!con.isClosed()){  
                        con.close();  
                    }  
                }  
            }  
              
        }  
    }
pmlm

ribclauport:
Realmente a explicação foi fantástica a respeito de como funciona o banco,
porém veja bem, eu setei na mão a coisa para commit true, como pode ser observado no código,
e continuou funcionando, discorpio, por favor poderia então me explicar por que está funcionando meu
código e não a do amigo que fez o post?

Creio que a classe de conexão do amigo que efetuou o post deveria ser analisada, ficariamos muito felizes se ele colocasse
a classe de conexão, por que acho que lá é que esta o problema.

Segue o código com auto commit true e mesmo assim funcionando.

O problema não está na conexão mas sim na Statement. Tu crias duas statatements, uma para o select e outra para o insert. O charleston10 deve estar a reutilizar a mesma Statement. Nesse caso, ao criar a Statement para o primeiro insert, fecha a anterior, fechando também o ResultSet

ribclauport

Então, obrigado ae pela resposta, porém, eu copiei o codigo do post, e criei as tabelas no banco e tal…

E charleston10 faz igual, cria um Statment para pesquisa, e um PreparedStatement para inclusão…

Sendo assim gostaria de saber o que a mega Explicação do amigo no post anterior tem haver com a situação.

charleston10

Galera, estou achando ótimo o tópico,
vale saber que eu ainda sou iniciante em java, e quero me aprofundar;
eu era programador em outra linguagem que não era OOP, vb6;

Muito boa as respostas;

Vai ai o código da classe de conexão da minha app

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package Classes;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import javax.swing.JOptionPane;

/**
 *
 * @author Charleston Gomes dos Anjos
 */
public class clsConexao {

    public String sSQL="";
    public static Connection cnn=null;
    public static Statement sta;
    public static boolean Conectado;
    public static ResultSet res;
    
    public clsConexao(){
        
    }        

    public void Conectar(){
        
        String caminho="h:/GLIDB.FDB";
        String url="jdbc:firebirdsql:localhost:" + caminho; //3050
        String usuario="SYSDBA";
        String senha="masterkey";

    try
        {
            //nesse momento estou registrando o driver do banco que vou acessar
            Class.forName("org.firebirdsql.jdbc.FBDriver");
            cnn = DriverManager.getConnection(url,usuario,senha);
            sta = cnn.createStatement();
            Conectado = true;
            //JOptionPane.showMessageDialog(null, "Conexão estabelecida");
        } catch(Exception ex) {JOptionPane.showMessageDialog(null, "Erro de conexão: \n\n" + ex);Conectado=false;}
         
    }

}

Eu penso o mesmo;

O problema não está na conexão mas sim na Statement. Tu crias duas statatements, uma para o select e outra para o insert. O charleston10 deve estar a reutilizar a mesma Statement. Nesse caso, ao criar a Statement para o primeiro insert, fecha a anterior, fechando também o ResultSet

Estou querendo mudar de banco de dados do meu projeto, pois o firebird em segurança é péssimo;
pretendo por o MySQL;

ribclauport

A questão principal ae no post é que existe a afirmação citada acima de que cada instrução SQL é logo após realizado um Commit e a conexão é fechada.
Porém eu testei o código usando um só Prepared Statement e Funcionou.
Consultei a documentação e existe a afirmação que quando se fecha um Statement o ResultSet atrelado a ele também é fechado…
Mas é fato na situação do amigo que não está sendo fechado o ResultSet…, então na verdade surge uma questão e acretido que até é bem bacana:

“É correto usar o mesmo Statement ou PreparedStamente na execução de duas intruções SQL?”

Não sei se sim, mas é fato, funciona!

charleston10

Pintou a mesma dúvida,

mas o que eu fiz quando isso aconteceu, eu criei outra Statement e PreparedStamente distintas da Seleção de dados com a da Inserção de dados e mesmo assim ocorreu o mesmo erro;

o pior de tudo que minha app tava fluindo na programação, mas congelou nessa parte, fiquei dias procurando na internet e resolvi colocar aki no guj, eu tava desanimando,
mas nada que a persistencia com animo nao resolva…

=]

pmlm

Um commit não implica que a conexão seja fechada, somente diz que as instruções até aquele ponto são finais, não podendo haver rollback.

Em relação ao código inicial, porque não fazes o insert directamente a partir da tabela temporária?

INSERT INTO PRODUTOS_VENDIDOS_CRIACAO(CODIGO_VENDA,CODIGO_PRODUTO,DESCRICAO,VALOR,QTDE,TOTAL) SELECT CODIGO_VENDA,CODIGO_PRODUTO,DESCRICAO,VALOR,QTDE,TOTAL FROM TABELA_TEMP

Mesmo que isto resolva o teu problema, tenho curiosidade em saber qual o erro que está a ocorrer. Podes por erro.printStackTrace(); e mostrar o resultado?

discorpio

Boa noite a todos.

Pessoal, quero [color=red]pedir desculpas por um erro meu e aproveitar para corrigí-lo.[/color]

O que na verdade me ocorreu é que eu fiz confusão de conexão com transação.

Então vamos a mais uma explicação lógica:

Após fazer uma analise mais apurado sobre JDBC, verifiquei que realmente a conexão uma vez estabelecida, ela não se fecha até que o usuário a requeira através de um Connection.close().

O que realmente se fecha, isto com o AutoCommit setado para true, é exatamente a transação, onde cada transação executa um statement por vez. É o que ocorre no código do Ribclauport onde é criada uma nova instância de um statement a cada passagem do loop while, mesmo com a mesma instrução SQL.

O que o nosso amigo Pmlm está totalmente correto, eis que o primeiro statement que a SQL que apanha os dados, [color=red]monta um ResultSet configurado como cursor bidirecional somente para leitura:[/color]

Statement sta = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);

E é claro, se voce tentar utilizar o mesmo statment que foi utilizado pela mesma transação, transação esta que foi fechada, fechando também o statment, deixando apenas o ResultSet ativo, porém somente para leitura.

Já com o AutoCommit setado para false, a transação não é aberta a cada instrução de atualização SQL (Insert, Update, Delete), esta transação só será aberta quando o usuário invocar o comando Commit, e neste caso, varias sentenças statement podem ser atreladas a uma única transação que efetuará o Commit em lote, o problema desta última opção, que se houver as famigeradas intemperes citadas pelo autor do post, voce tem que tratar uma exceção invocando o comando Rollback, para que a transação seja fechada, deixando a persistência de dados no Cliente ainda intacta, ainda assim se voce fechar a aplicação e se esquecer de efetuar o Commit, tudo que foi feito, irá por água abaixo,

O que coroborou para aumentar a minha confusão, é que eu trabalho com um pool de conexões. Quando você usa um pool de conexões, em vez de você abrir uma conexão no início de sua aplicação e fechá-la só quando sua aplicação terminar, um container que gerencia conexões de dados como o Apache Tomcat, abre várias conexões com o mesmo banco, no Servidor, e quando o usuário se loga pela primeira vez a este Servidor através do Tomcat, o Tomcat simplesmente conecta uma de suas conexões a usuário e quando o usuário fecha a aplicação ou seção de internet, esta conexão é devolvida ao TomCat. Dentro do TomCat, voce configura inclusive o número de conexões inativas permitidas e um Timeout especificando o tempo máximo que a aplicação poderá ficar conectada a conexão sem nenhuma frequência de transações abertas e executadas, desconectando-a da aplicação, onde o usuário terá que fazer nova autenticação de login, isto evita esses problemas de conexões que caem sozinhas depois de algum tempo.

Para maiores esclarecimentos, analisem os links abaixo, onde um deles voce baixa uma arquivo PDF sobre JDBC.

ftp://ftp.unicamp.br/pub/apoio/treinamentos/linguagens/curso_java_III.pdf.
http://www.devmedia.com.br/articles/viewcomp.asp?comp=4113.

Um abraço.

ribclauport

Bom, atualmente estou trabalhando com jpa, e muitas coisas ficam realmente transparentes ao progamador com esta abordagem,
Sendo assim gostaria também muito que o amigo criador do post, colocasse o bendito trecho abaixo a pilha de erro como disse nosso amigo
pmlmt, segue:

catch (Exception erro) {  
            	erro.printStackTrace();
                JOptionPane.showMessageDialog(null,  
                        "Erro gravar produtos listados\n\n " + erro);
charleston10

Como pedido, a descrição do erro, respectivamente:

[b]erro.printStackTrace();[/b]

                   ->> [color=red]gravarorg.firebirdsql.jdbc.FBSQLException: The resultSet is closed[/color]

                   [b]JOptionPane.showMessageDialog(null,    
                    "Erro gravar produtos listados\n\n " + erro);  [/b]  

                   ->> [color=red]org.firebirdsql.jdbc.FBSQLException: The resultSet is closed[/color]
charleston10

Atualmente meu código esta assim:

public void PegaGravaProdutosListados() throws SQLException {
       

       Banco.sSQL = "SELECT * FROM TEMP";

       Statement sta = Banco.cnn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
       ResultSet res = sta.executeQuery(Banco.sSQL);

       try{
             //Pega todos registros adicionados na lista
             
             while(res.next()){

                String sSQLCad = "INSERT INTO PRODUTOS_VENDIDOS(CODIGO_VENDA,CODIGO_PRODUTO,DESCRICAO,"
                + "VALOR,QTDE,TOTAL)"
                + "VALUES(?,?,?,?,?,?)";

                try{

                    PreparedStatement pst = Banco.cnn.prepareStatement(sSQLCad);

                    pst.setInt(1, res.getInt("CODIGO_VENDA") );
                    pst.setInt(2, res.getInt("CODIGO_PRODUTO"));
                    pst.setString(3, res.getString("DESCRICAO"));
                    pst.setFloat(4, res.getFloat("VALOR"));
                    pst.setInt(5, res.getInt("QTDE"));
                    pst.setFloat(6, res.getFloat("TOTAL"));
                    pst.execute();

                 }catch(SQLException erro){
                    erro.printStackTrace();
                    JOptionPane.showMessageDialog(null, "Erro gravar" + erro);
                 }

             }

         }catch(SQLException erro){
                JOptionPane.showMessageDialog(null, "Erro gravar produtos listados1\n\n " + erro);
         }finally{            
                if(res!=null&&!res.isClosed()){
                    res.close();
                }
                if(sta!=null&&!sta.isClosed()){
                    sta.close();
                }        
         }
    }
pmlm

charleston10:
Como pedido, a descrição do erro, respectivamente:

[b]erro.printStackTrace();[/b]

                   ->> [color=red]gravarorg.firebirdsql.jdbc.FBSQLException: The resultSet is closed[/color]

  </blockquote>

Mostra toda a stack, não apenas a primeira linha.

Vingdel

discorpio:
Boa noite a todos.

[…]

O que o nosso amigo Pmlm está totalmente correto, eis que o primeiro statement que a SQL que apanha os dados, [color=red]monta um ResultSet configurado como cursor bidirecional somente para leitura:[/color]

Statement sta = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);

E é claro, se voce tentar utilizar o mesmo statment que foi utilizado pela mesma transação, transação esta que foi fechada, fechando também o statment, deixando apenas o ResultSet ativo, porém somente para leitura.

[…]

Para maiores esclarecimentos, analisem os links abaixo, onde um deles voce baixa uma arquivo PDF sobre JDBC.

ftp://ftp.unicamp.br/pub/apoio/treinamentos/linguagens/curso_java_III.pdf.
http://www.devmedia.com.br/articles/viewcomp.asp?comp=4113.

Um abraço.

Pelo que consta na documentação, o ResultSet é fechando na situação de o Statement ser fechado.

http://docs.oracle.com/javase/6/docs/api/java/sql/ResultSet.html

Acho que esse é o problema, não?

Abraço!

discorpio

Boa tarde a todos.

Sinceramente também não consegui detectar onde está dando erro de ResultSet fechado, pois assim como o nosso amigo Ribclauport, fiz um teste aqui e também funcionou perfeitamente, mesmo com o AutoCommit estando setado para true.

Outra coisa que verifiquei, e que quando voce cria uma conexão, mesmo se voce omitir o setAutoCommit, por default ele é configurada como true.

Após analisar a sua classe de Conexão, só não entendi porque voce declarou um statement lá:

.....
      Class.forName("org.firebirdsql.jdbc.FBDriver");  
      cnn = DriverManager.getConnection(url,usuario,senha);  
      sta = cnn.createStatement();  // Qual a função deste statement.
      Conectado = true;
      .....

Possa que eu esteja mais uma vez enganado, porém não me canso de dar chutes em problemas (Trouble Shooting), após fazer uma outra análise de Conexão e ResultSet mai apurado, verifiquei que voce pode configurar um PrepareStatement para retornar um ResultSet que se fecha após um Commit ser realizado, eis as opções.

// Mantém o ResultSet aberto após Commit
  ResultSet.HOLD_CURSORS_OVER_COMMIT

  // Fecha o RelsultSet após Commit
  ResultSet.CLOSE_CURSORS_AT_COMMIT

Assim sendo voce pode mudar o Statement da tabela temporária para um PreparedStatement desta forma:

.....
   String sSQL = "SELECT * FROM tabela_temp";
   PreparedStatement sta = conn.prepareStatement(sSQL, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
   .....

Outa coisa que foi observada, e também não entendi até agora, a finalidade de voce criar este ResultSet Bidirecional (Navegável para adiante e retrocesso), se você está usando um loop while(res.next()) e não navega no ResultSet após o término do loop. Você pode simplesmente criar um ResultSet Unidirecional mesmo, pois você não navega nele dentro método e tão logo o método sai de scopo, o ResultSet, bem como o Statement são descartados pelo Garbage Collector, eis que eles são instâncias de scopo de métodos. Então:

.....
   PreparedStatement sta = conn.prepareStatement("SELECT * FROM tabela_temp");
   .....

O PreparedStatement acima lhe cabe muito bem dentro do método.

Um abraço.

charleston10

Gete deu certo.

O nosso amigo discorpio comentou algo sobre isso e estava certo;

Possa que eu esteja mais uma vez enganado, porém não me canso de dar chutes em problemas (Trouble Shooting), após fazer uma outra análise de Conexão e ResultSet mai apurado, verifiquei que voce pode configurar um PrepareStatement para retornar um ResultSet que se fecha após um Commit ser realizado, eis as opções. view plaincopy to clipboardprint?
// Mantém o ResultSet aberto após Commit  
ResultSet.HOLD_CURSORS_OVER_COMMIT
// Fecha o RelsultSet após Commit
ResultSet.CLOSE_CURSORS_AT_COMMIT

-

Sobre esse código:
.....  
Class.forName("org.firebirdsql.jdbc.FBDriver");    
cnn = DriverManager.getConnection(url,usuario,senha);    
sta = cnn.createStatement();  // Qual a função deste statement.  
Conectado = true;  

//Na vdd eu puxo essa sta em todas as classes do projeto, pra eu nao fica declarando toda vez; 
//Então ficaria

Banco.sta = Banco.cnn.prepareStatement(Banco.sSQL, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);

.....

Código funcionando beleza :)

public void PegaGravaProdutosListados() throws SQLException {

       clsVendas dReg = new clsVendas();

       Banco.sSQL = "SELECT * FROM TABELA_TEMP";
       
       PreparedStatement sta = Banco.cnn.prepareStatement(Banco.sSQL, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);

       ResultSet res = sta.executeQuery(Banco.sSQL);

       try{
             //Pega todos registros adicionados na lista             
             while(res.next()){              

                 String sSQLCad = "INSERT INTO PRODUTOS_VENDIDOS(CODIGO_VENDA,CODIGO_PRODUTO,DESCRICAO,"
               + "VALOR,QTDE,TOTAL)"
               + "VALUES(?,?,?,?,?,?)";

               try{

                   PreparedStatement pst = Banco.cnn.prepareStatement(sSQLCad);  

                   pst.setInt(1, res.getInt("CODIGO_VENDA") );
                   pst.setInt(2, res.getInt("CODIGO_PRODUTO"));
                   pst.setString(3, res.getString("DESCRICAO"));
                   pst.setFloat(4, res.getFloat("VALOR"));
                   pst.setInt(5, res.getInt("QTDE"));
                   pst.setFloat(6, res.getFloat("TOTAL"));
                   pst.execute();

                }catch(SQLException erro){                   
                   JOptionPane.showMessageDialog(null, "Erro gravar" + erro);
                }

             }
             
             sta.close();
             res.close();

         }catch(SQLException erro){
                JOptionPane.showMessageDialog(null, "Erro gravar produtos listados1\n\n " + erro);
         }finally{            
                if(res!=null&&!res.isClosed()){
                    res.close();
                }
                if(sta!=null&&!sta.isClosed()){
                    sta.close();
                }        
         }


    }

Obrigado pela ajuda de todos, realmente apanhei por vários dias nisso.
O tópico esclareceu varias coisas;

:D

Criado 14 de janeiro de 2012
Ultima resposta 20 de jan. de 2012
Respostas 24
Participantes 7