Exemplo usando Connection Pool

31 respostas
R

Fala galera…

alguem ae teria um exemplinho simples de como usar o DBCP da jakarta??
dei uma olhada nos exemplos lah do site dele, mas tem uns 3 exemplos lah e nao sei qual deles o melhor/ideal p/ usar…

valew

31 Respostas

maresp

Vc tá utilizando jdbc puro?

R

eh…apenas JDBC p/ conectar no banco…

R

Este aqui eu peguei lá mesmo.

Inclua isto no web.xml
<resource-ref>
        <description>Meu banco</description>
        <res-ref-name>jdbc/poolDB</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <res-auth>Container</res-auth>
    </resource-ref>
isto no context.xml
<ResourceLink name="jdbc/poolDB" type="javax.sql.DataSource" global="jdbc/poolDB"/>
agora no server.xml, colocando a url correta e aclasse correta do drive.
<Resource name="jdbc/poolDB" type="javax.sql.DataSource"/>
    <Resource name="jdbcDB" type="javax.sql.DataSource"/>
    <ResourceParams name="jdbc/poolDB">
      <parameter>
        <name>maxWait</name>
        <value>5000</value>
      </parameter>
      <parameter>
        <name>maxActive</name>
        <value>4</value>
      </parameter>
      <parameter>
        <name>password</name>
        <value>prs</value>
      </parameter>
      <parameter>
        <name>url</name>
        <value>jdbc:mysql://localhost:3306/seubanco</value>
      </parameter>
      <parameter>
        <name>driverClassName</name>
        <value>org.gjt.mm.mysql.Driver</value>
      </parameter>
      <parameter>
        <name>maxIdle</name>
        <value>2</value>
      </parameter>
      <parameter>
        <name>username</name>
        <value>root</value>
      </parameter>
    </ResourceParams>
Esta parte do server.xml o proprio tomcat pode fazer pra você. Entre no admin do tomcat e crie um data source lá passando a url e o drive. Usei a versão 5.028. cria uma classe para criar as conexões.
/*
 * Connection.java
 *
 * Created on 31 de Outubro de 2004, 16:12
 */


import java.sql.Connection;
import javax.sql.DataSource;
import javax.naming.Context;
import javax.naming.InitialContext;
import java.sql.SQLException;
import javax.naming.NamingException;
/**
 *
 * @author  regis
 */
public class Pool {    
    public Pool() {
    }
    public static Connection getConnection() {
        Connection conn = null;
        try {
            Context ctx = (Context) new InitialContext().lookup("java:comp/env");
            conn = ((DataSource) ctx.lookup("jdbc/poolDB")).getConnection();    
        } catch (Exception e) {
            e.printStackTrace(System.err);
        } 
    return conn;
    }
}
e usa ela assim:
con = Pool.getConnection();

Antes que você pense que há muito código, isto é o mínimo que precisa.

Espero ter ajudado, abraço.

Luca

Olá

Uma dica: para entender o DBCP é preciso entender também do jakarta-commons-pool. Baixe este cara e veja a API. Depois veja como configurar um DataSource com JNDI no tomcat. Os ResourceParams do server.xml são aqueles que fazem sentido com seu pool (no caso, dbcp e pool).

[]s
Luca

maresp

Bem, todo mundo já respondeu… mas vale a pena dar uma olhadinha aqui se tiver dúvidas.

R

valew pelas dicas, turma…

mas to usando o WAS como AppServer, nao tomcat…

mas valew…

W

Estou usando o exemplo mais simples que peguei no próprio site do projeto.
Não usei nenhuma configuração xml. Está funcionando bem.

import javax.sql.DataSource;

import java.sql.<em>;

import org.apache.commons.dbcp.BasicDataSource;

import java.util.Properties;

import <a href="http://java.io">java.io</a>.</em>;

import javax.servlet.ServletContext;
public class Dbpc {

private static Dbpc instance = null;

private DataSource ds;

private Connection con;

private String driver;

private String url;

private String login;

private String password;

private int maxConnections;

private long maxWait;
/** Creates a new instance of Dbpc */
public Dbpc() {
    Properties props = new Properties();
     try {
     
        InputStream fis = this.getClass().getClassLoader().getResourceAsStream("db.properties");                        
        props.load(fis);            
        fis.close();
    }
    catch(FileNotFoundException f) {
        System.out.println("File not found in Dbcp --> constructor.
" + f.getMessage());

f.printStackTrace();

}

catch(IOException ioex){

System.out.println("Error I/O in Dbpc --> constructor.

" + ioex.getMessage());

ioex.printStackTrace();

}

catch(Exception e) {

System.out.println("Error in Dbpc --> constructor.

" + e.getMessage());

e.printStackTrace();

}
//recuperando configuracoes de acesso ao db           
    driver = props.getProperty("driver");
    url = props.getProperty("url");
    login = props.getProperty("login");
    password = props.getProperty("password");
    maxConnections  = (new Integer(props.getProperty("maxConnections"))).intValue();
    maxWait = (new Long(props.getProperty("maxWait"))).longValue();        
    ds = setupDataSource();
}

public static Dbpc getInstance() {
  if(instance == null) {
     instance = new Dbpc();
  }
  return instance;
}

public Connection getConn() throws SQLException {
    return ds.getConnection();        
}

private DataSource setupDataSource() {
    BasicDataSource ds = new BasicDataSource();
    ds.setDriverClassName(driver);
    ds.setUsername(login);

    ds.setPassword(password);
    ds.setUrl(url);
    ds.setMaxActive(maxConnections);
    ds.setMaxWait(maxWait);
    ds.setDefaultAutoCommit(true);
    return ds;
}

public void printDataSourceStats() throws SQLException {
    BasicDataSource bds = (BasicDataSource) ds;
    System.out.println("NumActive: " + bds.getNumActive());
    System.out.println("NumIdle: " + bds.getNumIdle());
}

/*shutdown DataSource*/
public void shutdown() throws SQLException {
    BasicDataSource bds = (BasicDataSource) ds;
    bds.close();
}

}

Luca

Olá

Wendel, ótimo exemplo. Mas ficaria mais legal com identação entre Code e /Code. Veja dicas em: http://www.guj.com.br/forum/viewtopic.php?t=16594

[]s
Luca

R

valew pelas dicas pessoal…

mas eh o seguinte…o proprio WAS jah tem como implementar o Pool no servidor…
como banco, vou usar o DB2 e no pacote JDBC dele vi umas classes tb p/ fazer Pool…

ai fica a duvida…fazer ou nao no codigo o Pooling?? sera melhor deixar o servidor tratar disso??

T

Em servidores de aplicações (como o WAS, o Sun Java System, o JBoss etc.) normalmente a gente só obtém uma conexão a partir de um java.sql.DataSource, e a implementação de DataSource é que faz o connection pooling. Para devolver a conexão ao pool de conexões, basta fechá-la corretamente.
A única coisa chata é que a Connection que o DataSource retorna é aquela Connection bastante genérica; se você precisa usar algum recurso do banco de dados que não está exposto via JDBC puro, você precisa fazer umas mágicas.
Por exemplo, teve uma vez que tive de passar BLOBs como parâmetros para stored procedures no Oracle e também ARRAYs e objetos Oracle, e isso só consegui fazer direitinho (incluindo o problema da limitação de tamanho de BLOBs…) usando oracle.jdbc.internal.OracleConnection e outras rotinas no pacote oracle.jdbc; então tive que fazer uma pequena mágica - normalmente o objeto Connection retornado pelo DataSource é um wrapping da conexão “nativa” para o banco. Então tive de checar se o objeto Connection retornado pelo DataSource era um org.jboss.resource.adapter.jdbc.WrappedConnection (no caso do JBoss), e se fosse, ele tem um método getUnderlyingConnection, que retorna a conexão como um objeto oracle.jdbc.internal.OracleConnection.

Rubem_Azenha

só de usar Singleton com DAO ja não cria um pool por assim dizer?

Lucas_Teixeira

Hum… eu acho que o conceito de um pool de conexões vai muito além de um “acessa-o-banco-e-manda-pra-ca”. Um pool vai estar gerenciando não só o request de conexões, mas também a quantidade de conexões ativas, a configuração do DataSource, e dentro de cada uma destas, muitas outras configurações.

Em nosso projeto, estamos usando o c3p0 que está dando conta do recado muito bem. Sua configuração é trivial e ele faz tudo de maneira muito transparente. Acho que é uma boa saida.

Rubens Microfilo, o conceito de Singleton não está descartado, afinal o pool deve ser único :wink:

(:

Rubem_Azenha

hum

legal

digamos que eu esteje usando DAO e singleton

digamos que eu queira limitar o numero de conexão ha 17 conexões simultaneas

o que vcs acham dessa solução

public class ConexaoDAO
{

private static ConexaoDAO instancia = null;
private static int numConexoes = 0;
private static final int MAX_CONEXOES = 17;

private ConexaoDAO()
{
//código para conectar ao BD
//bla bla bla bla bla 
//bla bla bla
//bla bla bla
}

public static ConexaoDAO getConexaoDAO() throws TooManyConnectionsException
{

if (nunConexoes >= MAX_CONEXOES)
{
  throws new TooManyConnectionsException("ERRO! MUITAS CONEXÕES", MAX_CONEXOES);
}
numConexoes++;
if (instancia  == null)
 instancia = new ConexaoDAO;
return instancia
}


//getters...
}

seria uma coisa assim?

PS: Meu nome é RubeM (primogênito de Jacó), não RubeNS(piloto de F1) :lol:

cv1

Singleton = ruim. Use um pool de verdade. :wink:

Lucas_Teixeira

Só cuidado no decremento da variável de contagem.

Olha um exemplo meu com o c3p0

/*
 * Criado em Dec 30, 2004
 * Lucas Frare Teixeira
 * [email removido]
 */
package br.filadelfia.connection;

import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.SQLException;

import org.apache.log4j.Logger;

import com.mchange.v2.c3p0.ComboPooledDataSource;

/**
 * @author Lucas Teixeira - <a
 *         href="mailto:[email removido]">[email removido] </a>
 */
public class ConnectionPool {

    static Logger log = Logger.getLogger(ConnectionPool.class); 
    private static ComboPooledDataSource cpds;
    
    private ConnectionPool() {
    	//Singleton é bonito
    }
    
    public static Connection getConnection() throws PropertyVetoException, SQLException  {
    	if (cpds == null) {
            cpds = new ComboPooledDataSource();
            cpds.setDriverClass("org.gjt.mm.mysql.Driver");
            cpds.setJdbcUrl("jdbc:mysql://localhost:3306/dbunifil");
            cpds.setUser("root");
            cpds.setPassword("root");
            cpds.setMinPoolSize(10); 
            cpds.setAcquireIncrement(5); 
            cpds.setMaxPoolSize(50);
            cpds.setAcquireRetryAttempts(3);
            //cpds.setMaxIdleTime(60);
        }
        log.info("Pool forneceu conexão.");
        return cpds.getConnection();
    }
}

Mal pelo nome.

Rubem_Azenha

CV: o pool não é o controle do numero de conexões??? o que falta na minha classe para se tornar um poorl de conexões?

caiofilipini

Um pool de conexões não controla somente o número de conexões que devem ser estabelecidas. Além disso, ele ainda deve controlar o timeout das conexões, fechamento de conexões inativas por um determinado tempo, etc…

[]'s

Rubem_Azenha

a tAh…

vai além do meu conhecimento no momento…

Lucas_Teixeira

microfilo:
a tAh…

vai além do meu conhecimento no momento…

Para isso existem APIs prontas de implementações de Pool… o c3p0 faz tanta coisa, e tudo de um modo tão transparente. Capaz de usar uma camiseta: “c3p0, foi bom para vc tb?”

Rubem_Azenha

eu prefiro tentar aprender como funciona, como implementar, etc, mesmo que eu use alguma coisa pronto…

do mesmo modo que eu achei uma grande vantagem ter tido a matéria estruturas de dados, apesar das colections

cv1

Um bom jeito pra fazer isso entao eh ler o codigo das “coisas prontas” antes de assumir que voce sabe de tudo que tem que fazer e sair reinventando a roda. Existe talvez mais de uma dezena de connection pools opensource por aih, entao tenha certeza de estudar bem o codigo deles. Garantido que vc vai aprender muito :wink:

F

Além disso da pra aproveitar esse “estudo de codigo” e ainda colaborar com o projeto, corrigindo bugs, incrementando funcionalidades. No fim das contas aprende e ainda colabora.

]['s

tiagops

Pessoal, desenterrando essa Trhead :slight_smile:

Estou tentando fazer o connection pool seguindo o exemplo do Régis Steigleder, mas com certeza estou fazendo algo errado, pois estou recebendo a seguinte mensagem de erro :

<blockquote>form.isInd_proc_canc() = false

org.apache.commons.dbcp.SQLNestedException: Cannot create JDBC driver of class ‘’ for connect URL ‘null’

at org.apache.commons.dbcp.BasicDataSource.createDataSource(BasicDataSource.java:780)

at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:540)

</blockquote>

o meu arquivo Web.xml esta com o seguinte trecho

<resource-ref>
<description>DESENVOLVIMENTO</description>
<res-ref-name>jdbc/poolDB</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</web-app>

o arquivo contect.xml esta igual ao exemplo. Esse arquivo eu criei na mao.

o arquivo server.xml esta assim :

<?xml version='1.0' encoding='utf-8'?>

<Server>
<Listener className=“org.apache.catalina.mbeans.ServerLifecycleListener”/>
<Listener className=“org.apache.catalina.mbeans.GlobalResourcesLifecycleListener”/>
<GlobalNamingResources>
<Environment value=“30” type=“java.lang.Integer” name=“simpleValue”/>
<Resource type=“org.apache.catalina.UserDatabase” description=“User database that can be updated and saved” auth=“Container” name=“UserDatabase”/>
<Resource type=“javax.sql.DataSource” name=“jdbc/poolDB”/>
<ResourceParams name=“UserDatabase”>
<parameter>
<name>factory</name>
<value>org.apache.catalina.users.MemoryUserDatabaseFactory</value>
</parameter>
<parameter>
<name>pathname</name>
<value>conf/tomcat-users.xml</value>
</parameter>
</ResourceParams>
<ResourceParams name=“jdbc/poolDB”>
<parameter>
<name>validationQuery</name>
<value> </value>
</parameter>
<parameter>
<name>maxWait</name>
<value>5000</value>
</parameter>
<parameter>
<name>maxActive</name>
<value>20</value>
</parameter>
<parameter>
<name>password</name>
<value>masterkey</value>
</parameter>
<parameter>
<name>url</name>
<value>jdbc:firebirdsql://192.168.0.1:3050/DESENVOLVIMENTO</value>
</parameter>
<parameter>
<name>driverClassName</name>
<value>org.firebirdsql.jdbc.FBDriver</value>
</parameter>
<parameter>
<name>maxIdle</name>
<value>4</value>
</parameter>
<parameter>
<name>username</name>
<value>sysdba</value>
</parameter>
</ResourceParams>
</GlobalNamingResources>
<Service name=“Catalina”>
<Connector connectionTimeout=“20000” port=“8080” redirectPort=“8443” disableUploadTimeout=“true” acceptCount=“100” maxThreads=“150” minSpareThreads=“25” maxSpareThreads=“75”>
</Connector>
<Connector port=“8009” redirectPort=“8443” protocolHandlerClassName=“org.apache.jk.server.JkCoyoteHandler” protocol=“AJP/1.3”>
</Connector>
<Engine defaultHost=“localhost” name=“Catalina”>
<Host appBase=“webapps” name=“localhost”>
<Logger className=“org.apache.catalina.logger.FileLogger” suffix=".txt" prefix=“localhost_log.” timestamp=“true”/>
</Host>
<Logger className=“org.apache.catalina.logger.FileLogger” suffix=".txt" prefix=“catalina_log.” timestamp=“true”/>
<Realm className=“org.apache.catalina.realm.UserDatabaseRealm”/>
</Engine>
</Service>
</Server>

Alguem pode me dar uma luz?

Obrigado!

tiagops

Pessoal, apanhei quase 3h antes postar a mensagem e agora consegui resolver.

Agora eu criei o datasource dentro do contexto da aplicação no TomCat e deu certo!
:idea:

Obrigado! :smiley:

marcelomartins

Aproveitando o topico e sem querer mudar de foco, to fazendo uns testes com o pool de conexoes do tomcat, e usando JDBC, percebi que cada vez que eu abro um statement ele abre uma conexao com o banco.

Por exemplo, quando eu crio o pool, ele nao abre nenhuma conexao, quando eu pego uma conexao e abro um statment ele abre uma conexao com o banco. Se eu abrir outro statement, antes de fechar o primeiro fica com 2 conexoes no banco. Percebi que ele abre uma conexao pra cada statement.

Ai vem minhas duvidas. Como vou conseguir controlar a transacao se ele pega duas conexoes? Vi uns exemplos usando uma UserTransaction, mas nao achei isso no tomcat.

Alguem pode me dar uma luz?

PS: Desculpem a falta de acentos :slight_smile:

tiagops

marcelomartins, como voce faz pra saber quantas conexões foram abertas pelo TomCat ?

marcelomartins

Vou no gerenciador do banco e verifico quantas conexoes estão abertas, o pool não fecha elas depois que abriu :wink:

Ah, e no caso, meu ambiente de testes é usando MSSQL :?

pedroabs

Implementei a minha Connection Pool:

http://pedroabs.wordpress.com/2011/09/27/connection-pool-em-java-pool-de-conexoes/

pedroabs

Eu implementei um exemplo de connection pool e atualmente uso-o na minha aplicação web:

http://pedroabs.wordpress.com/2011/09/27/connection-pool-em-java-pool-de-conexoes/

Luiz_Augusto_Prado

Olá pessoal.
Postei um fonte sobre o asunto aqui e queria trocar ideias sobre ele. Ver outras sugestões e criticas.

caiofilipini:
Um pool de conexões não controla somente o número de conexões que devem ser estabelecidas. Além disso, ele ainda deve controlar o timeout das conexões, fechamento de conexões inativas por um determinado tempo, etc…
[]'s

Estou atento ao que o caiofilipini disse e inclui o timeout.
A ideia é fazer o programa funcionar em singleton jogando um parametro PoolJDBC com as propriedades que eu quero na conexão.

A interface PoolJDBC é onde crio as propriedades da conexão.
ConnectionDB implementa a interface Connection
ConnectionPool é a classe da qual o Teste extende e é responsavel pelo controle do pool de conexões.

Luiz_Augusto_Prado

Por que seria ruim?
Poderia me falar mais sobre isso?

Criado 5 de novembro de 2004
Ultima resposta 28 de out. de 2011
Respostas 31
Participantes 15