Excesso de conexões no banco de dados

20 respostas
H

boa tarde.

tenho um programa de suporte técnico (helpdesk) aq na empresa onde trabalho que eu fiz. só que tenho um problema na minha conexão, toda vez que atendo um chamado novo, ele abre novas conexões no bd. Quando atendo muitos chamados, ele adiciona muitas conexões no banco de dados. Há mais um programa que compartilha o mesmo servidor, então acaba lotando o numero de conexões. Há alguma forma do meu programa gerar menos conexões?

Segue o código abaixo.

package utilitarios;
import java.sql.*;
import javax.swing.*;


public class conexao
{
final private String driver = "com.mysql.jdbc.Driver"; //aula 29
    final private String url ="jdbc:mysql://localhost:3306/hospital";
    final private String usuario ="usuario";
    final private String senha = "12345";
    private Connection conexao;
    public Statement statement;
    public ResultSet resultset; 
    
 public boolean conecta()
 {
     boolean result = true;
     try
     {
         Class.forName(driver);
         conexao = DriverManager.getConnection(url, usuario, senha);
        // JOptionPane.showMessageDialog(null,"Conectou!");
                         
     }
     catch(ClassNotFoundException Driver)
     {
         JOptionPane.showMessageDialog(null,"Driver não localizado: "+Driver);
         result = false;
     }
     catch(SQLException Fonte)
     {
         JOptionPane.showMessageDialog(null,"Ocorreu um erro na conexão " +
                "com a fonte de dados: "+Fonte);
         result = false;
         
     }
     
     return result;
}

public void desconecta()
{
    boolean result = true;
    try
    {
        conexao.close();
        JOptionPane.showMessageDialog(null,"Banco fechado");
    }
    catch(SQLException fecha)
    {
        JOptionPane.showMessageDialog(null,"Não foi possível fechar "+
                "o banco de dados: "+fecha);
        result = false;
    }
}    

public void executasql(String sql)
{
    try
    {
        statement = conexao.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_READ_ONLY);
        resultset = statement.executeQuery(sql);
    }
    catch(SQLException sqlex)
    {
        JOptionPane.showMessageDialog(null,"Não foi possível "+
                "executar o comando, "+sqlex+", o comando passado foi: "+sql);
    }
}

}

Aqui é uma tela do programa, eu estou chamando a minha classe de conexão.

public hd_server() {
        initComponents();
        
        
        
        con_setores = new conexao();
        con_setores.conecta();
        
        con_hdsf = new conexao();
        con_hdsf.conecta();
       
        con_atualiza = new conexao();
        con_atualiza.conecta();
        
        con_ordena = new conexao();
        con_ordena.conecta();
        
        con_ordatual = new conexao();
        con_ordatual.conecta();

Cada chamada dessa é uma conexão nova, é o que faz lotar o banco.

Agradeço a ajuda de todos.

Até mais

20 Respostas

E

a) Você criou o método desconecta, quem é que chama esse método? Quando ele é chamado?

b) Para esse tipo de problemas, é aconselhável usar pools de conexões. Só não se esquecer que, depois de usar uma conexão do pool, você deve fechá-la o mais rápido possível (ou seja, devolvê-la ao pool).

H

Antes de mais nada, obrigado pela resposta. Vamos as respostas.

a) Então meu amigo, eu peguei esse código de uma video aula, sou meio iniciante ainda em java. O cara criou a conexão desconecta mas não ensinou a usar. Toda vez que fecho a conexão, dá pau no programa.

b) Ouvi falar de pool de conexão mas não sei usar ainda, poderia me indicar um link para eu dar uma estudada?

grato!

A

Olá Boa Tarde, hishin

Eu colocaria a conexão em uma classe ConnectionFactory, sendo assim uma fabrica de conexões…

public class ConnectionFactory {   
  
    public Connection getConnection() {   
  
        try {   
            return DriverManager.getConnection("jdbc:mysql://localhost/fj21", "root", "");   
        } catch(SQLException e) {   
            throw new RuntimeException(e);   
        }   
    }   
}

Colocaria no no contrutor da classe de manipulação a Conexão…sendo assim você não se preocupa em ficar instanciando a todo momento…

public class ContatoDAO {   
    private Connection connection;   
  
    public ContatoDAO() {   
        try {   
            this.connection = new ConnectionFactory().getConnection();   
        } catch (SQLException e) {   
            throw new RuntimeException(e);   
        }   
    }

E na hora de manipular o metodo você já fecha a conexao após o uso…

public void adiciona(Contato contato) {   
        try {   
            String sql = "insert into contatos (nome, email, endereco, dataNascimento) values (?,?,?,?)";   
            PreparedStatement stmt = connection.prepareStatement(sql);   
             //Set/Get do que você precisa 
            stmt.execute();  //Executa o que você quiser 
            stmt.close();   //Fecha o que estiver sendo executado...Conexão
        } catch (SQLException e) {   
            throw new RuntimeException(e);   
        }   
    }

Espero ter te ajudado…

abraços

H

orras!! terei que mudar todo o codigo, mas tentarei sim. vlw!

vo testar e depois eu posto aqui.

ate mais.

PS: Se alguem tiver mais idéias, posta ai.

J

hishin, você não pode manter as conexões abertas o tempo todo.

O correto é abrir a conexão, fazer a consulta, guardar os dados num objeto ou mesmo num List ou Map e fechar a conexão, e usar os dados vindos desse objeto, mas nunca manter a conexão aberta.

E um rápido aviso, o código do AndreSorge tem um problema, pois se ocorrer uma exceção a conexão não será fechada, então vai uma regra: sempre feche conexões no bloco finnaly

H

Então amigo, ouvi falar desse list, mas não sei como usar. acho que o que o AndreSorge é um list não é?

o que seria um Map?

vlw!!

A

Opa pessoal é isso mesmo, desculpe fiz código na mão e acabei deixando de fora isso…sempre finalize o bloco Try/cath com o finally bem lembrado pelo juliofsn

Abaixo segue um exemplo de um List

public List<Contato> getLista() {
		try {
			List<Contato> contatos = new ArrayList<Contato>();
			PreparedStatement stmt = this.connection.prepareStatement("select * from contatos");

			ResultSet rs = stmt.executeQuery(); //Executa o select

			while(rs.next()) { //Roda até chegar no final do select
				Contato contato = new Contato();
				//popula o objeto contato
				contato.setId(rs.getLong("id"));
				contato.setNome(rs.getString("nome"));
				contato.setEmail(rs.getString("email"));
				contato.setEndereco(rs.getString("endereco"));

				//popula a data de nascimento do contato, fazendo a conversao
				Calendar data = Calendar.getInstance();
				data.setTime(rs.getDate("dataNascimento"));
				contato.setDataNascimento(data);

				//adiciona o contato na lista
				contatos.add(contato);
			}

			return contatos; //Retorna o objeto populado
		} catch (SQLException e) {  //Erro no Select
			throw new RuntimeException(e);  
			rs.close();
			stmt.close();
		}finally{ 
			rs.close(); //Fecha o ResultSet
			stmt.close();   //Fecha a conexão
		}
	}

Espero ajudar…abraços a todos…

H

boa tarde!

vlw pelas respotas. Mas tenho um problema hehe.

Esse list eh um método nao é? então… ele dá erro qdo adiciono no meu código.

Esse aq é o método que criei baseado no q foi passado aq. Mas ele dá erro sozinho e fiz os imports que o netbeans pede.

public List<cad_user> getLista() {
        try {
            List<cad_user> contatos = new ArrayList<cad_user>();
            PreparedStatement stmt = conexao.prepareStatement("select * from contatos");

            ResultSet rs = stmt.executeQuery(); //Executa o select

            while(rs.next()) { //Roda até chegar no final do select
                cad_user contato = new cad_user();
                //popula o objeto contato
                contato.setId(rs.getLong("id"));
                contato.setNome(rs.getString("nome"));
                contato.setEmail(rs.getString("email"));
                contato.setEndereco(rs.getString("endereco"));

                
                

                //adiciona o contato na lista
                contatos.add(contato);
            }

            return contatos; //Retorna o objeto populado
        } catch (SQLException e) {  //Erro no Select
            throw new RuntimeException(e);
            con_login.resultset.close();;
            con_login.statement.close();
        }finally{
            con_login.resultset.close(); //Fecha o ResultSet
            con_login.statement.close();   //Fecha a conexão
        }
    }

oq está acontecendo?

vlw!!

A

Manu, faz o seguinte tem como mandar o erro do List?

Você ta importando do java.util*
?

H

A mensagem de erro é: “missig return statement”

Gostaria de perguntar também onde são criados os métodos utilizados para popular o objeto (setId, por exemplo).

Obrigado pela ajuda.

A

Opa vamos lá então…eu copiei o seu código e fiz em casa…olhá só…vamos tirar o bloco Finally por enquanto, pois ele tava dando erro aqui em casa também…aqui não deu esse erro que você disse manu…
olha só vou postar aqui 3 classes…ConnectionFactoryContato…e ContatoDao

ConnectonFactory

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


public  class ConnectionFactory {     

	public Connection getConnection() {     

		try {     
			return DriverManager.getConnection("jdbc:mysql://localhost/fj21", "root", "");     
		} catch(SQLException e) {     
			throw new RuntimeException(e);     
		}     
	}     
}

Contato

import java.util.Calendar;


public class Contato {

	private long id;
	private String nome;
	private String email;
	private String endereco;
	private Calendar dataNascimento;
	
	public Contato(){
		
	}
	
	public Calendar getDataNascimento() {
		return dataNascimento;
	}

	public void setDataNascimento(Calendar dataNascimento) {
		this.dataNascimento = dataNascimento;
	}

	public long getId() {
		return id;
	}
	public void setId(long id) {
		this.id = id;
	}
	public String getNome() {
		return nome;
	}
	public void setNome(String nome) {
		this.nome = nome;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	public String getEndereco() {
		return endereco;
	}
	public void setEndereco(String endereco) {
		this.endereco = endereco;
	}
}

Você perguntou de onde veio o SetId e os Outro correto? Então e com eles os Set/Get que agente manipula as variáveis…
Entendeu?

ContatoDao

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;


public class ContatoDao {

	private Connection con;

	public ContatoDao() throws SQLException{
		this.con = new ConnectionFactory().getConnection();
	}


	public List<Contato> getLista() {  
		try {  
			List<Contato> contatos = new ArrayList<Contato>();  
			PreparedStatement stmt = this.con.prepareStatement("select * from contatos");  

			ResultSet rs = stmt.executeQuery(); //Executa o select  

			while(rs.next()) { //Roda até chegar no final do select  
				Contato contato = new Contato();  
				//popula o objeto contato  
				contato.setId(rs.getLong("id"));  
				contato.setNome(rs.getString("nome"));  
				contato.setEmail(rs.getString("email"));  
				contato.setEndereco(rs.getString("endereco"));  

				//popula a data de nascimento do contato, fazendo a conversao  
				Calendar data = Calendar.getInstance();  
				data.setTime(rs.getDate("dataNascimento"));  
				contato.setDataNascimento(data);  

				//adiciona o contato na lista  
				contatos.add(contato);  
				rs.close();  
				stmt.close();  
			}  

			return contatos; //Retorna o objeto populado  
		} catch (SQLException e) {  //Erro no Select  
			throw new RuntimeException(e);    
		}  
	}  	
}

Se você copiar e colar desse jeito ele não deve dar erro nenhum…acabei de testar aqui em casa…copia e cola…não dando erro ou dando erro você posta que agente coloca o bloco finally e encerra a conexão e o ResultSet…

Vlw Abraços, posta ai o resultado…

Obs.: Não se esqueça do Driver do MySql…

A

Melhorando…

Sempre que você ultiliza o Try/Catch tem que ter o bloco Finaly…independente o que aconteça o bloco Finaly sempre será executado…

H

boa tarde.

Caro AdreSorge, muito obrigado pela sua ajuda.

Agora vamos aos detalhes hehe.

A classe deu certo, não aparece erro, porém… como eu puxo os dados nos formulários? poderia me dar um pequeno exemplo? (se não for pedir demais :slight_smile: )

Muito grato pela ajuda!!

até mais

A

Esse form que você está falando seria o em que? Swing ou Web?

Você consegue popular os objetos?

Vamos ao um exemplo bem tosqueira…

public class TestaContato{
        
      Contato con = new Contato(); /*Instancia um Contato*/
      ContatoDao conDao = new ContatoDao();/*Instancia um ContatoDao*/

      con.setNome(JOptionPane.showInputDialog("Digite um nome: "));/*Neste ponto você já está "populando" a variável*/
      /*.....*/
      System.out.println(con.getNome());/*Você irá imprimir no console o nome que você digitou no JOptionPane*/ 

      conDao.inserirNoBanco(con); /*Você passa o objeto já populado para o método "inserirNoBanco" que já está esperando o Contato*/

Entendeu? Se ficou qualquer duvida, posta ai que eu tento te dar mais alguns exemplos…

H

boa tarde.

Meu software é swing.

Então cara… meu programa está cheio de bugs… e terei que tratar desses erros até fazer algo funcionar. Pelo menos consegui ele abrir o formulario. eu tenho um método que chama “mostrar dados”, onde quando eu abro a tela, o formulario já carrega os dados. O método não está funcionando, ele carrega zerado.

mas isso eu estou vendo aq. na semana que vem eu posto aq novamente.

Muito grato pela sua ajuda!

Até mais!

A

Esse método Mostrardados() ele é um select no banco e monta um List correto?

Vou fazer um bem legal com Swing…ai eu posto aqui para você…

abraços e até mais…

H

Bom dia, tentei fazer algo assim:

public void mostrar_dados()
    {
         try
        {
            
            Usuario us = new Usuario();
            UsuarioDao usDao = new UsuarioDao();
            usDao.getLista();
            tf_codigo.setText(Integer.toString(us.getId()));
            tf_nome.setText(us.getNome());
            tf_senha.setText(us.getSenha());
            cb_acesso.setSelectedItem(us.getNivel());
           
            
           
        }
        catch(SQLException erro)
        {
              JOptionPane.showMessageDialog(null, "Não localizou dados "+erro);
         }

Mas tenho quase certeza de que está errado, pois apesar de não apontar nenhum erro ele não puxa os dados.

Muito grato pela ajuda.

Até Mais.

A

Opa manu, vamos tentar assim…

Criando uma classe de modelo…

public class Cliente{
     
     private String nome;
     private int idade;

    public Cliente(){  /*Contrutor*/
    }

        /*Métodos Set's/Get's é com ele que agente manipula os dados*/
        /*Set você utiliza para "Colocar ou Setar" algum valor recebido dentro de uma determinada variável*/
        /*Get você utiliza para "Pegar" algum valor contido dentro de uma determinada variável*/

    public void setNome(String nome){ /*Método que recebe uma String nome*/
             this.nome=nome;      /*"Seta" o valor que veio como parâmetro, dentro da variável 'nome' da classe Cliente*/
    }

    public String getNome(){ /*Não recebe nada como parâmetro*/
             return nome;      /*Retorna o que estiver na variável 'nome' da classe Cliente*/
    }

   public int setIdade(int idade){
              this.idade=idade;
   }
 
    public void getIdade(){
            return idade;
    }
}

Bom já temos as variáveis, agora temos de popular elas correto?, então vamos lá:

public class TestaCliente {

            public static void main(String arg[]){

                 Cliente cliente = new Cliente();/*Criamos uma variável do tipo Cliente, então todo o modelo de cliente está dentro dela*/
                 /*Se você quiser ver se está tudo certo, digite cliente. de um CTRL + Barra de espaço, ele irá trazer todo os métodos nativos e mais os que você criou (Set/Get)Vamos testar?*/
                 cliente.setNome(JOptionPane.showInputDialog("Digite o seu nome: "));/*Neste ponto o que você digitar irá ser inserido na variável nome da classe Cliente, por causa do Set*/
                 cliente.setIdade(Integer.parseInt(JOptionPane.showInputDialog("Digite a idade: ")));

                 ClienteDao clienteDao = new ClientesDao();

                 clienteDao.adiciona(cliente);
              }
}

Beleza, até agora só criamos a classe de modelo…agora vamos para uma conexão com o banco de dados…

import  java.sql.Connection;         
import java.sql.DriverManager;         
import java.sql.SQLException;         
           
public  class ConnectionFactory {             
         
     public Connection getConnection() { /*Método que retorna uma conexão*/             
         
        try {             
            return DriverManager.getConnection("jdbc:mysql://localhost/fj21", "root", ""); /*fj21 = nome do banco de dados, root = usuário do bando e "" a senha do bando de dados  */           
        } catch(SQLException e) {/*Tratamento de erro*/             
            throw new RuntimeException(e);             
        }             
    }

Maravilha, já temos uma classe de modelo, e já estamos conectando no banco de dados…agora vamos fazer uma classe DAO, que irá inseri e selecionar alguns dados no banco…

public class ContatoDAO {   
    private Connection connection;   /*Variável do tipo Connection*/
  
    public ContatoDAO() {   /*Contrutor, colocamos a conexão nelo, pois assim todos os métodos desta classe possam utilizar a conexão, sem precisar instanciar a todo momento*/
        try {   
            this.connection = new ConnectionFactory().getConnection();/*Executa o método getConnection da classe ConnectionFactory*/   
        } catch (SQLException e) {   /*Caso de algum erro*/
            throw new RuntimeException(e);   
        }   
    }   
       
       
    public void adiciona(Cliente clie) { /*Método que está recebendo uma variável do tipo Contato*/  
        try {   
            String sql = "insert into cliente (nome, idade) values (?,?)"; /*Neste ponto você cria uma variável do tipo String que recebe como parâmetro a query SQL*/ 
            PreparedStatement stmt = connection.prepareStatement(sql); /*O PreparesStatement é que faz a execução da String Sql, mais para isso ela precisa da conexão*/   
  
            /*Aqui é aonde eu acho que você está amarrado...*/
            /*Vou explica icone por icone: stmt = variável do tipo PreparedStatement já carregada com a conexão e a String sql no gatinho. o setString representa que você irá colocar na String sql um valor do tipo texto (String), lembra que eu comentei que tudo que estiver dentro do () do set, é o que ele tentara "setar" em algum lugar? neste caso é a mesma coisa, ele irá pegar o valor que estiver dentro da variável nome da classe Cliente pelo método getNome(), e você deve estar se perguntando que raios de número 1 é esse ai....bom se você repara na String sql, tem umas ?,? cada numero significa uma ?, então de tivermos 30 ? teremos de 1 a 30 realizando os set's adequado. Sendo mais rápido o que ele irá fazer eh isso: String sql = "INSERT INTO cliente (nome, idade) values ('João', 12);"...entendeu????*/
            stmt.setString(1, clie.getNome());   
            stmt.setString(2, clie.getIdade());   
              
            stmt.execute();/*Neste ponto ele irá executar o comando SQL dentro do bando de dados*/   
            stmt.close();   /*fecha a conexão*/
        } catch (SQLException e) {   /*Caso de algum erro na execução das instruções acima*/
            throw new RuntimeException(e);   /*Captura o erro em tempo de execução*/
        }   
    }

Entendeu? Caso não fala ai manu que eu tento te dar outro exemplo…

no código que você fez, você está tentando pegar o retorno do select e depois setar nas variaveis…entendeu?

H

Bom dia. blz??

As classes que vc passou funcionaram mas ainda assim tenho problemas, pois como é muito novo esse tipo de estrutura do código, ainda estou com dificuldades.

vamos lá!

o meu método “mostrar-dados” é um modo q exibe os dados nos campos do formulário assim que ele carrega, porém com esse novo modo ainda não consegui exibi-los.

Meu projeto já está pronto e tenho dados no banco, o problema está na hora de carregar os dados, ainda não testei o gravar/alterar/excluir. assim q eu conseguir fazer funcionar esse método “mostrar-dados” funcionar, partiremos pra proxima etapa.

Grato pela sua ajuda e paciencia.

abraços!

A

Opa manu, desculpa a demora…vou te dar um exemplo de SELECT blz…vamos até o momento que mostra na tela…tendo o objeto populado já é grande coisa…pois ai você pode manipular do jeito que você quiser…
Vamos reaproveitar a classe de ConnectionFactory, e Cliente e o ClienteDao…

import java.sql.Connection;  
  import java.sql.PreparedStatement;  
  import java.sql.ResultSet;  
  import java.sql.SQLException;  
  import java.util.ArrayList;  
  import java.util.Calendar;  
  import java.util.List;  
     
   public class ContatoDao {  
     
      private Connection con;  
     
       /*Colocamos a conexão no construtor para que agente não precise instanciar a todo o momento*/   
       public ContatoDao() throws SQLException{  
           this.con = new ConnectionFactory().getConnection();  
       }  
     
     /*Esse é o método que está te tirando o sono*/
       public List<Cliente> getLista() { /*Método que retorna uma lista de clientes*/   
           try {    
               List<Cliente> clientes = new ArrayList<Cliente>();    /*qAqui você cria uma lista de clientes do tipo Cliente*/
               PreparedStatement stmt = this.con.prepareStatement("select * from cliente");    /*Prepara para executar uma ação no banco*/
     
               ResultSet rs = stmt.executeQuery(); //Executa o select    
    
               while(rs.next()) { //Roda até chegar no final do select    
                   Cliente cliente = new Cliente();/*Instancia um Cliente para popular o objeto*/    


                   cliente.setNome(rs.getString("nome")); /*Olha o set aqui de novo, vamos lah, você está "Setando" dentro da variável nome da classe cliente, o rs vem do ResultSet, é ele que percorre o select executado, então ele irá percorrer a primeira coluna o qual é uma String, por isso o GetString ou seja, "Pegue uma String", e o que está entre as "" é o nome do campo no banco de dados. Fica mais ou menos assim "Pegue uma String no campo nome do banco de dados, e coloque o valor que você achar lá dentro da variável nome da classe cliente"*/   
                   cliente.setIdade(rs.getInt("idade"));  /*É o mesmo esquema do de cima*/  
     
                   clientes.add(cliente);    /*Aqui, depois que o ResultSet rodar a primeira vez, ou seja, depois que ele já ter populado o primeiro objeto, ele irá adicionar na lista*/
                 
               }    
                   rs.close();  /*Fecha o ResultSet*/  
                   stmt.close();  /*Fecha a conexao*/  
               
                   return clientes; //Retorna todos os objetos populados    
           } catch (SQLException e) {  //Erro no Select    
               throw new RuntimeException(e);      
           }    
       }     
  }

Beleza já temos a nossa lista populada, vamos mostrar ela na tela.

public class TestaCliente

 public static void main (String args[]){

ClienteDao clienteDao  = new ClienteDao();

/*Olha só uma coisa que eu percebi no seu código é que você está instanciando o Cliente também na classe de teste, se você fizer isso você irá apagar tudo que você populou, então neste caso nós não instanciamos ciente e sim clienteDao*/

	List<Cliente> clientes = clienteDao.getLista(); /*Cria uma lista de cliente executando o método da classe clienteDao, então você pegou aquela lista e colocou em outra, assim você pode acessa-la em outras classes sem precisar instanciar e perder tudo que você fez*/

			for (Cliente cliente : clientes){ /*Faz um forEach para rodar a lista nova de Clientes*/
				System.out.println(cliente.toString()); /*Mostra o toString da classe cliente sem instanciar ela, pois você criou uma variável do tipo cliente no ForEach assim não recria o objeto*/
			}/*não esquece de sobre escrever o método toString da classe Cliente*/

Então manu assim agente retornou do banco os dados que contem nele…espero ter ajudado…qualquer coisa posta a que eu tento te ajudar…se quiser tenta postar o código seu para agente analisar junto…abracos e boa sorte;…

Criado 16 de junho de 2010
Ultima resposta 25 de jun. de 2010
Respostas 20
Participantes 4