Qual a melhor maneira de pegar uma conexão?

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?

[code] 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;
    }
}

}[/code]

Um exemplo de sua utilização:

[code] 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;
}[/code]

Valeu!

  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

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!

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

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:

[code] 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 );
}

}[/code]

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.

???

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