Qual a melhor maneira de pegar uma conexão?

5 respostas
Luiz_Henrique_Coura

Galera, estou com uma dúvida cruel.

Criei essa classe para me fornecer uma funcinalidade muito util: Conexões ao Banco de Dados.

Pensei em fazer essa classe pq toda hora criamos aplicações q conectam ao BD. Assim diminuo meu trabalho! :wink:

O Problema é q não sei se estou fazendo de maneira correta.

O q vcs acham dessa forma q estou utilizando?

Como vcs costumam fazer?

public abstract class UtilBDConnection {
    /**
     * Pegar conexões por DataSource
     */
    public static Connection getConnectionByDataSource( String myDS ) throws Exception {
        Context context = new InitialContext();
        
        DataSource dataSource = (DataSource)context.lookup( myDS );
        
        return dataSource.getConnection();
    }

    /**
     * Pegar conexões por parâmetros
     */
    public static Connection getConnectionByParameters( String url, String user, String password, String DRIVER ) throws Exception {
        Class driverClass = Class.forName( DRIVER );
        
        return DriverManager.getConnection( url, user, password );
    }
    
    /**
     * Fechar conexão
     */
    public static void closeConnection( Connection connection, Statement statement, ResultSet resultSet ) throws Exception {
        if( resultSet != null ) {
            resultSet.close();
            resultSet = null;
        }
        
        if( statement != null ) {
            statement.close();
            statement = null;
        }
        
        if( connection != null ) {
            connection.close();
            connection = null;
        }
    }
}
Um exemplo de sua utilização:
public List list() throws Exception {
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        
        List list = new ArrayList();
        
        try {
            connection = UtilBDConnection.getConnectionByDataSource( "java:comp/env/jdbc/CMMySQL" );
            
            statement = connection.createStatement();

            resultSet = statement.executeQuery( "SELECT * FROM test" );
            while( resultSet.next() ) {
                list.add( resultSet.getString(1) );
            }
        } finally {
            UtilBDConnection.closeConnection( connection, statement, resultSet );
        }
        return list;
    }

Valeu!

5 Respostas

Rafael_Steil
  1. Voce nao esta usando um connection pool
  2. Voce nao esta fechando os result sets e statements
  3. Voce esta duplicando varias linhas de codigo ao pegar a conexao, tratar o erro e fechar a conexao em cada metod.

Dica: utilize um template method

Rafael

Luiz_Henrique_Coura

Rafael, estou utilizando o pool do Tomcat. Configuro ele no context da aplicação. Mas o q vc quiz dizer é q seria melhor trabalhar com um pool independente do container, tipo DBCP ou C3PO?

A respeito de fechar as conexões, eu passo, além do objeto connection, o statement e o resultSet para o método UtilBDConnection.closeConnection( connection, statement, resultSet ). Nesse método ele fecha tudo.

Na questão dos tratamentos de erros, realmente, preciso tratá-los direto no método.

Valeu pela dica do Template Method!

Rafael_Steil

Ok, mas e se vc precisa se mais statements e resultsets? vai ficar meio estranho fechar um pouco num canto e o resto em outra parte…

Rafael

Luiz_Henrique_Coura

Rafael, qd vc quiz dizer: "duplicando linhas de código", é pq toda hora eu preciso chamar o método UtilBDConnection.getConnectionByDataSource( "java:comp/env/jdbc/CMMySQL" ) para conseguir uma conexão?

E o mesmo acontece com UtilBDConnection.closeConnection( connection, statement, resultSet ) ao fechar conexão?

Isso não tem nada a ver com o fato de eu estar trabalhando com métodos static, certo?

Já com TemplateMethod eu usaria um "esqueleto" de uma classe abstrata na qual eu teria um método getConnection() e closeConnection() que fariam esse papel pra mim?

E se eu implementasse esses métodos com uma chamada a minha classe? Assim:

public abstract class TemplateMethod() {
    public abstract void getConnection();
    public abstract void closeConnection();
    public abstract List list();

    public final List execute() {
        getConnection(); //Abre a conexão
        List list = list(); //Faz a pesquisa
        closeConnection(); //Fecha a conexão
        return list; //Retorna o resultado    
    }
}

public class ConcreteClass() extends TemplateMethod {
    private final String myDS = "java:comp/env/jdbc/CMMySQL";

    private Connection connection = null;
    private Statement statement = null;
    private ResultSet resultSet = null;

    //Implementei utilizando minha classe UtilBDConnection
    public void getConnection() { 
        connection = UtilBDConnection.getConnectionByDataSource( myDS );
    }

    public List list() {
        ////Faço minha consulta
    }

    //Implementei utilizando minha classe UtilBDConnection
    public void closeConnection() {
        UtilBDConnection.closeConnection( connection, statement, resultSet );
    }
}

Eu poderia até criar um outro método para fechar minhas conexões, mantendo minha conexão aberta e fechando somente o statement e o resultSet, para poder reutilizar a mesma connection.

????

Rafael_Steil

Quase. Pegar a conexao e tratar erros sao coisas do template. As classes filhas somente fazem o execute. Ficaria assim:

public abstract class TemplateMethod() {
     private Connection connection;

     public TemplateMethod() {
          this.connection = this.openConnection();
     }

     private Connection openConnection() {
          // abre a conexao com o banco
     }

      protected Connection getConnection() {
          return this.connection;
     }

     private void closeConnection() {
          // fecha / libera a conexao
     }

     public abstract Object doAction() throws Exception;
 
     public final Object execute() {
          try {
              return this.doAction(); 
          }
          catch (Exception e) {
               throw new AlgumaRuntimeExceptionTua(e);
          }
          finally {
              this.closeConnection(); 
          }
     }
 }

e entao, para usar, vc faz algo como

TemplateMethod t = new TemplateMethod() {
    public Object doAction() throws Exception {
        Statement s = this.getConnection();

        // Trabalha com o banco

        return algumaCoisa;
    }
}.execute();

Veja que pegar a Exception no execute() e relancar uma RuntimeExeption eh para te livrar da necessidade de fazer try-catch nos lugares onde vc for usar o pattern.
Como voce ver, o seu codigo fica muito mais limpo, focando-se apenas na parte importante da tarefa.

Rafael

Criado 29 de junho de 2005
Ultima resposta 30 de jun. de 2005
Respostas 5
Participantes 2