Duvida com fechamento de statement e resultSet

24 respostas
S

Galeraa…

Eu tenho um pacote com varias classes q acessam o banco de dados…
E cada metodo tem o seguinte no fim:

finally{ try{ BD.resultSet.close(); BD.statement.close(); catch(SQLException e){ e.printStackTrace(); } }

soh q isso esta fechando a conexao com o banco…nao sei pq rsrs

alguem pode dar uma ajuda!?

Desde já agradeço!

24 Respostas

S

coloca o stmt.close() após o retorno do metodo que estiver chamando… faz um teste.

S

continua dando o mesmo erro…

e o pior eh q esse erro nao acontece toda hora…ele acontece de vez enquando…
e soh em 2 metodos q sao chamados por uma thread…

sera q tem algo haver isso?

S

e quando da o erro ele seta nesse comando:

BD.setResultSet(sql);

segue o metodo do setResultSet

public static void setResultSet(String sql) throws SQLException{ if(status==false){ BD.getConnection(); } statement= connection.createStatement(); resultSet= statement.executeQuery(sql); }

S

ele da nullPointerException…

Mas a string sql q eu passo pra ele tem valor q eu jah conferi :S

S

corrigindo…

Eu testei aqui e ele nao fecha a conexão naoo…ela continua “ligada”…

ele da a seguinte exception:

java.lang.NullPointerException at com.mysql.jdbc.StatementImpl.useServerFetch(StatementImpl.java:2567) at com.mysql.jdbc.StatementImpl.executeQuery(StatementImpl.java:1353) at metodos.BD.setResultSet(BD.java:103) at beansDb.PendenciaDb.getPendenciasAtivas(PendenciaDb.java:218) at metodos.ThreadVerificaPendencia.run(ThreadVerificaPendencia.java:26) at java.lang.Thread.run(Thread.java:619)

e ele seta essa linha na classe do banco:

resultSet= statement.executeQuery(sql);

e tambem no metodo seta essa linha:

BD.setResultSet(sql);
V

O finally em si está certo.

Mas outras coisas nesse código cheiram a POG, e dos feios.

O resultset e o statement não deveriam ser propriedades da classe BD, muito menos públicas. É necessário criar um Statement diferente por thread. E é também recomendável fechar a conexão no finally.

Como a conexão é um recurso demorado de ser obtido, o ideal é também usar o apache DBCP ou o C3P0 para fazer um pool de conexões.

Do jeito que está, ambas as threads compartilham o mesmo resultset e statement. Sem falar que as propriedades estão excessivamente permissivas, permitindo, por exemplo, que um programador as defina para null.

S

putss…era isso mesmo :S

Vlw pela ajuda ae emm!!!

Abraços!

S

mas ja que você (Vini) chegou a esse assunto…rs

como seria a forma correta de criar os statments, resultSets e a propria conexão com o banco!?

eh necessário cada vez q eu for fazer uma consulta, inserção, exclusão, alteração, etc., no banco eu tenho q criar um novo resultSet!?

Desde já agradeço!

X

Ta meio estranho mesmo isso…

Como já foi dito, em uma situação de concorrência sua classe vai dar pau - ai você lasca um syncronized e perde a vantagem do paralelistmo.

Mas o que está mais estranho é a classe TER uma instância de ResultSet, e se outra Thread mandar executar o método setResultSet quando uma outra thread ainda está lendo os resultados anteriores?

Melhor você rever algumas questões de desenho desta classe.

Dê uma olhada no DBUtils da apache: http://commons.apache.org/dbutils/examples.html

Veja como é feito, eu acho show de bola aquilo ali. :smiley:

S

entaoo…para isso eu fiz um Gambiarra suahsuahsuahsa…
pq esse projeto ja ta muito adiantado…e ai eu preciso terminar ele logo…e depois quando tiver mais tempo eu volto pra consertar algumas coisas rsrs…

pq o q eu fiz pra consertar foi o seguinte:

eu criei 3 resultSets, 3 statements e 3 metodos setResultSet…

aiii…qualqer operação eu mando pra o resultSet1…uma thread vai no setResultSet2, e a outra thread vai para o setRresultSet3…

eh uma puta gambiarra…mas por enquanto vo te q dexa assim rsrs…
depois eu volto pra consertar…rsrs

X

Égua mah, faz isso não bixo, depois vai dar problemas e o culpado, é você!
Diz que precisa de mais tempo e pronto.

S

entaoo…mas se eu for concertar eu teria q fazer o q exatamente?

S

o meu metodo setResultSet alem de receber a sql teria q receber tmbm o resultSet e o statement?

S

eu criei o seguinte metodo na classe do banco:

public static ResultSet setResultSet(ResultSet rs, Statement st, String sql) {
		try {
			st= connection.createStatement();
			rs= st.executeQuery(sql);        
	        status = true;    
	    }
		catch(Exception e){
	        new StackTrace(e, sql, "setResultSet");
	    }  
		return rs;
	}

e ae eu chamo ele no metodo assim:

ResultSet rs = null;
Statement st = null;

try
{
	rs = BD.setResultSet(rs, st, "SELECT * FROM usuario WHERE usuario='"+usuario+"' AND senha='"+senha+"'");
	rs.next();
	if (rs.getRow()>0)
	{		
		if(rs.getString("status").equals("1")){
			res = "0";
		}
		else{
			Geral.usuario = new Usuario(rs.getInt("id_usuario"), rs.getString("nome_usu"),rs.getShort("admin"),rs.getString("configuracao"), rs.getInt("status"));
					res = "1";
		}
}
catch(Exception e){
    e.printStackTrace();
}

esta eh a forma correta?

S

ou eu nem precise do metodo setResultSet?

fazendo da seguinte forma:

Statement st = null;
		ResultSet rs = null;
		
		String res = "2";
		try
		{
			st = BD.connection.createStatement();
			rs = st.executeQuery("SELECT * FROM usuario WHERE usuario='"+usuario+"' AND senha='"+senha+"'");
			
			rs.next();
.......

qual eh a maneira correta?

F

Shoker, na boa!

Acho que vc construiu uma “arapuca” e está pulando para dentro com tudo.

Se o código da classe BD não for muito grande tente inclui-la em um post para a galera dar uma olhada e tentar construir uma solução mais segura e mais organizada pra te ajudar.

flws

S

a classe bd soh tem os metodos getConnection, setResultSet, runSQL e close.

Mas eu qeria sabe se na hora q eu for fazer um setResultSet seria melhor ao invez de eu chamar o metodo eu fazer o seguinte:

ex:

public Metodo(){
  Statement st = null;
  ResultSet rs = null;
  String sql = "";
  
  try{
    st = BD2.connection.createStatement();
    sql = "sql aqui";
    rs = st.executeQuery(sql);  
    //continua...
  }
  catch(Exception e){
    //tratamento
  }
}
F

Pelo jeito a classe BD é pequena, porem tem muita coisa nela que parece não estar muito bem. O controle da conexão é um exemplo.

Já deu uma olhada na DbUtils indicada pelo camarada anteriormente? Parece uma boa idéia.

P.S Inclua o código da classe BD em um post pelo menos pra gente te falar os problemas.

flws

V

Não é correta. Se você incluir a palavra “static”, dificilmente estará usando a forma correta.
Infelizmente, não é tão trivial te explicar como é a forma correta.

Entretanto, para uma correção simples no seu código essa forma está adequada. Só marque esse método também como synchronized para que duas threads não tentem acessa-lo ao mesmo tempo.

S

segue a classe BD:

public class BD {
	public static Connection connection = null;
	public static Statement statement = null;
	public static ResultSet resultSet = null;
	public static String banco;
	public static boolean status;

	public static void main(String args[]) {
		getConnection();
		close();
	}

	/**
	 * m�todo que faz conex�o com o banco de dados Access
	 * retorna true se houver sucesso, ou false em caso negativo
	 */

	public static boolean getConnection() {
		status = false;
		Criptografia criptografia = new Criptografia();
		
		banco=("jdbc:mysql://"+Geral.configuracao.getServidor()+"/"+Geral.configuracao.getBanco()+"?user="+Geral.configuracao.getUsuario()+"&password="+criptografia.decryptString(Geral.configuracao.getSenha()));

		try {
			Class.forName("com.mysql.jdbc.Driver");
			connection= DriverManager.getConnection( banco );
			status=true;
			System.out.println("++CONECTOU CLIENTE");
} catch(ClassNotFoundException e) {
			new StackTrace(e, "", "BD1").setVisible(true);	
		} catch(SQLException e) {
			new StackTrace(e, "", "BD2").setVisible(true);
		}
		return status;
	}


	/**
	 * Fecha ResultSet, Statement e Connection
	 */
	public static void close() {
		try {
			connection.close();
			status=false;
			System.out.println("--DESCONECTOU CLIENTE");
		} catch(SQLException erro) {
			new StackTrace(erro, "", "BD3").setVisible(true);
		}
	}


	/**
	 * Carrega o resultSet com o resultado do script SQL
	 */
	public static void setResultSet(String sql){
		try{
			statement= connection.createStatement();
			resultSet= statement.executeQuery(sql);        
	        status = true;    
	    }
		catch(Exception e){
	        new StackTrace(e, sql, "setResultSet");
	    }  
	}
	
	/**
	 * Executa um script SQL de atualiza��o
	 * retorna um valor inteiro contendo a quantidade de linhas afetadas
	 * @throws SQLException 
	 */
	public static int runSQL(String sql) throws SQLException {
		int quant = 0;	
			statement= connection.createStatement();
			quant = statement.executeUpdate(sql);
//			System.out.println(sql);
//			System.exit(0);
		
		return quant;
	}
}
X

DBUtils, e a JDBCTemplate do Spring: http://static.springsource.org/spring/docs/2.0.x/reference/jdbc.html

Veja como ela faz a execução das query’s. Cada método fica independente de thread, pois cada um cria sua conexão (e é ai onde o Pool tem importância), cria seu statement, lê seu resultado e retorna, tudo dentro do método é independente da classe.

S

mas Vini…qual das duas formas q eu coloquei esta mais correta!?
a que chama o metodo setResultSet e passa os parametros ou a q eu crio a statement e o resultSet sem chamar o metodo setResultSet?

X

No lugar do seu setResultSet, eu faria um método do tipo:

public object[] executarQuery(String sql){
		
		Connection conn = getConnection();//Vinda do Pool
		
		object[] retorno = bla bla...
		Statement stmt = null;
		ResultSet rs = null;
		try {
			stmt = conn.createStatement();
			String query = "select * from bla bla bla";

			rs = stmt.executeQuery(query);

			while(rs.next()){
				//transforme o RS em objetos.
			}
		} catch (Exception e) {
			//bla bla bla
		} finally {
			try {rs.close();} catch (SQLException e) {}
			try {stmt.close();} catch (SQLException e) {}
			try {conn.close();} catch (SQLException e) {}
		}
		return retorno ;
	}

Algo parecido, mas pelo menos dessa forma, fica independente de thread, pois cada execução do método é independente de outra.

O seu getConnection também carrega drivers toda vez que você vai obter uma conexão, e isso só é necessário uma vez:

...
Criptografia criptografia = new Criptografia();  
           
       banco=("jdbc:mysql://"+Geral.configuracao.getServidor()+"/"+Geral.configuracao.getBanco()+"?user="+Geral.configuracao.getUsuario()+"& password="+criptografia.decryptString(Geral.configuracao.getSenha()));  
   
         try {  
       Class.forName("com.mysql.jdbc.Driver"); 
...

O certo mesmo seria usar o Pool, principalmente se cada chamada ao método executarQuery criar uma nova conexão.

S

mas quando eu abro o programa ele cria a conexão…
depois ela soh eh fechada quando o programa eh fechado…

Criado 16 de junho de 2010
Ultima resposta 16 de jun. de 2010
Respostas 24
Participantes 5