Problemas com DAO - Variável 'conn' global é fechada no mesmo momente que fecho a var 'conn' local

Olá pessoal

Comecei a desenvolver minhas classes DAO para meu trabalho de conclusão de curso e estou tendo um problema. Na verdade eu já consegui resolver o problema fazendo “gambiarra”, porém esta não é a melhor solução. Por este motivo gostaria da ajuda de vocês.

O problema é: Quando executo um método DAO, por exemplo um select(), a conexão que pertence a classe é fechada ao mesmo tempo que fecho somente a conexão do método. Porque? Não consegui entender o porque. Fiz duas variáveis do tipo Connection na minha classe UsuarioDaoImp justamente para a variável global permanecer ativa enquanto estiver trabalhando com objeto, e somente fechar as variávies locais do tipo Connection.

Fiz um código exemplo que segue os mesmos esquemas da minha classe: Veja

Classe Usuario

[code]public class Usuario {

private int id;
private String usuario;
private String senha;

/**
 * @return the id
 */
public int getId() {
    return id;
}

/**
 * @param id the id to set
 */
public void setId(int id) {
    this.id = id;
}

/**
 * @return the usuario
 */
public String getUsuario() {
    return usuario;
}

/**
 * @param usuario the usuario to set
 */
public void setUsuario(String usuario) {
    this.usuario = usuario;
}

/**
 * @return the senha
 */
public String getSenha() {
    return senha;
}

/**
 * @param senha the senha to set
 */
public void setSenha(String senha) {
    this.senha = senha;
}

}[/code]

Interface UsuarioDao

[code]public interface UsuarioDao {

Usuario select(int cod) throws Exception;

}[/code]

Classe UsuarioDaoImp

[code]import br.com.persistencia.dao.conect.Conectar;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
*

  • @author Leandro
    */
    public class UsuarioDaoImp implements UsuarioDao {

    Connection conn = null; // -> Esta conexão é fechada no mesmo momento
    // -> que eu fecho a conexão do método

    public UsuarioDaoImp() throws Exception{
    conn = new Conectar(
    “com.mysql.jdbc.Driver”,
    “jdbc:mysql://localhost/livraria?user=root&password=”).getConector();
    }

    public Usuario select(int cod) throws Exception{

     Usuario usu = null;
     PreparedStatement ps = null;
     Connection conn = null;
     ResultSet rs = null;
    
     try{
         conn = this.conn;
         ps = conn.prepareStatement("SELECT usuario, senha FROM usuarios where id=?");
         ps.setInt(1, cod);
         rs = ps.executeQuery();
    
         usu = new Usuario();
    
         while(rs.next()){
             usu.setSenha(rs.getString(1));
             usu.setUsuario(rs.getString(2));
         }
         
         ps.close();
         rs.close();
         
     }catch (SQLException ex){
         throw new SQLException(ex);
     }catch (Exception ex){
         throw new Exception(ex);
     }finally{
         conn.close(); // --> A intenção aqui é somente
                      // fechar conexão do método e não o da classe
     }
     return usu;
    

    }
    }[/code]

Fiz duas chamas do método select da classe UsuarioDaoImp

[code] Usuario us = usu.select(1);
System.out.println("usuário: "+us.getUsuario());
System.out.println("Senha: "+us.getSenha());

  Usuario US = usu.select(2);
        System.out.println("usuário: "+US.getUsuario());
        System.out.println("Senha: "+US.getSenha());[/code]

E recebi as seguintes repostas

[quote]usuário: teste1
Senha: teste1

java.sql.SQLException: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: No operations allowed after connection closed.
at pkTeste.UsuarioDaoImp.select(UsuarioDaoImp.java:53)
at pkTeste.TestadorDeMetodos.main(TestadorDeMetodos.java:54)
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: No operations allowed after connection closed.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:406)
at com.mysql.jdbc.Util.getInstance(Util.java:381)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:984)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:926)
at com.mysql.jdbc.ConnectionImpl.checkClosed(ConnectionImpl.java:1098)
at com.mysql.jdbc.ConnectionImpl.prepareStatement(ConnectionImpl.java:4076)
at com.mysql.jdbc.ConnectionImpl.prepareStatement(ConnectionImpl.java:4042)
at pkTeste.UsuarioDaoImp.select(UsuarioDaoImp.java:38)
… 1 more[/quote]

Porque será que a conexão da variável de escopo global conn (Connection) é fechada no momento que é fechada a conexão da viarável com o mesmo nome só que de escopo local?

Obrigado

[]

Brother,

tu nao precisa ter uma variável conn dentro dos métodos. Usa direto conn da variável de classe.

Esta era “gambiarra” que estava falando. Vlw pela dica.

Como sou curioso, você conseguiria me explicar o comportamente das duas são mudadas ao mesmo tempo?

Isto acontece porque você está atribuindo a uma outra variavel do tipo Connection a referência para o objeto conn, criado no momento da instanciação do seu DAO. O que ocorre é que qualquer alteração feita no objeto dentro do método vai refletir fora deste, uma vez que você está modificando valores de um atributo (variavel de instancia). Embora você utilize uma outra referência para isto o objeto referenciado é o mesmo.

Espero ter ajudado.

Relmente é isto meso. Antes de postar eu troquei o nome da variável global e continuou dando o mesmo erro. Obrigado pela explicação.

Neste caso, como boa prática e solução para meu problema, é certo eu iniciar uma conexão no momento que eu declarar a varável do tipo Connection? E quais riscos posso correr não fechando a conexão ao termino de um método DAO?

[code]public class UsuarioDaoImp implements UsuarioDao {

private Connection conn = new Conectar(
            "com.mysql.jdbc.Driver",
            "jdbc:mysql://localhost/livraria?user=root&password=").getConector(); // <<-- 

public UsuarioDaoImp() throws Exception{
}

public Usuario select(int cod) throws Exception{

    Usuario usu = null;
    PreparedStatement ps = null;
    ResultSet rs = null;

    try{
        ps = conn.prepareStatement("SELECT usuario, senha FROM usuarios where id=?");
        ps.setInt(1, cod);
        rs = ps.executeQuery();
 [...][/code]

Ou passar a conexão no próprio método de forma que possa gerenciar a conexão de DAOs diferentes em uma única classe (controller) também com uma única conexão.

[code] […]
public Usuario select(int cod, Connection conn) throws Exception{

    Usuario usu = null;
    PreparedStatement ps = null;
    ResultSet rs = null;
 [...]
public Usuario insert(Usuario usu, Connection conn) throws Exception{

    PreparedStatement ps = null;
 [...]
public Usuario update(Usuario usu, int id, Connection conn) throws Exception{

    PreparedStatement ps = null;
 [...][/code]

Pessoa, desculpe a insistência, mas alguém poderia me ajuda com minha dúvida? Por favor.

Levantei algumas questões mas a é esta: Fora, talves, um pouco mais de lentidão, quais riscos posso correr não fechando a conexão ao termino de um método DAO?

public Usuario select(int cod) throws Exception{ [...] }catch (Exception ex){ throw new Exception(ex); }finally{ conn.close(); // --> Não fechar a conexão aqui nesta linha } }

Obrigado mais uma vez