Problema com o pool de conexões DBCP do Tomcat

6 respostas
B

Diga pessoal, ja postei uma mensagem desta aqui no forum mas ainda não tive sucesso, o problema foi o seguinte:

Vou tentar passar também o que estou utilizando.
No server.xml tenho:

<Context path="/sistemas" docBase="sistemas" debug="0" reloadable="true" crossContext="true"> 
  <Resource name="jdbc/gerencial" auth="Container"   type="javax.sql.DataSource"/> 
  <ResourceParams name="jdbc/gerencial"> 
    <parameter> 
      <name>factory</name> 
      <value>org.apache.commons.dbcp.BasicDataSourceFactory</value> 
    </parameter> 
    <parameter> 
      <name>driverClassName</name> 
      <value>oracle.jdbc.driver.OracleDriver</value> 
    </parameter> 
    <parameter> 
      <name>url</name> 
      <value>jdbc:oracle:thin:@dbcluster:1521:dbprod</value> 
    </parameter> 
    <parameter> 
      <name>username</name> 
      <value>usuario</value> 
    </parameter> 
    <parameter> 
      <name>password</name> 
      <value>senha</value> 
    </parameter> 
    <parameter> 
      <name>removeAbandoned</name> 
      <value>true</value> 
    </parameter> 
    <parameter> 
      <name>removeAbandonedTimeout</name> 
      <value>300</value> 
    </parameter> 
    <parameter> 
      <name>logAbandoned</name> 
      <value>true</value> 
    </parameter> 
    <parameter> 
      <name>maxActive</name> 
      <value>10</value> 
    </parameter> 
    <parameter> 
      <name>maxIdle</name> 
      <value>3</value> 
    </parameter> 
    <parameter> 
      <name>maxWait</name> 
      <value>30000</value> 
    </parameter> 
  </ResourceParams> 
</Context>

E no web.xml:

<resource-ref> 
    <description>Pool de conexoes da WebCoruripe</description> 
    <res-ref-name>jdbc/gerencial</res-ref-name> 
    <res-type>javax.sql.DataSource</res-type> 
    <res-auth>Container</res-auth> 
</resource-ref>

E a minha classe eh a seguinte:

public class ConnectionBD implements servicos.comunicacao.Connection{ 

    private static DataSource ds; 

    private java.sql.Connection con; 
    private Statement statement; 

    private String driver; 
    private String url; 
    private String user; 
    private String password; 
    private String user; 
    private String password; 

    /** Faz a conexão com o banco. */ 
    public synchronized void connect() throws java.sql.SQLException { 
        try{
            if (!this.isConnected()){
            this.showOperation("Efetuando conexão com o banco..."); 
                this.statement = null; 
                this.preparedStatement = null; 
                this.lastComandPrepared = null; 
                if (this.ds == null){ 
                Context ctx = new InitialContext(); 
                this.ds = (DataSource)ctx.lookup("java:comp/env/jdbc/gerencial"); 
                } 
                this.con = this.ds.getConnection(); 
                System.out.println("Conexão: " + this.con); 
            } 
            this.showOperation("Ok."); 
        }catch(Exception e){ 
            throw this.makeSQLException(e, null); 
        } 
    }  

    /** Fecha a conexão com o banco */ 
    public synchronized boolean disConnect() {
        try{ 
            if (this.isConnected()){
                this.showOperation("Efetuando desconexão..."); 
                if (this.statement != null){ 
                    this.statement.close(); 
                    this.statement = null; 
                } 
                if (this.preparedStatement != null){ 
                    this.preparedStatement.close(); 
                    this.preparedStatement = null; 
                } 
                this.lastComandPrepared = null; 
                this.con.close(); 
                this.showOperation("Ok."); 
                System.out.println("Desconexão: " + this.con); 
                return true; 
            }else 
                return false; 
        }catch(Exception e){ 
            this.showOperation(e.toString()); 
            return false; 
        } 
    } 

    /** Retorna verdadeiro se a conexão esta aberta */ 
    public boolean isConnected() throws java.sql.SQLException { 
        try{ 
            this.showOperation("Verificando conexão..."); 
            boolean conectado; 
            if (con == null){ 
                conectado = false; 
            }else{ 
                conectado = ! con.isClosed(); 
            } 
            this.showOperation("Ok."); 
            return conectado; 
        }catch(Exception e){ 
            throw this.makeSQLException(e, null); 
        } 
    } 

    /** Executa a instrução SQL:INSERT, UPDATE,... com exceção do SELECT */ 
    public int executeUpdate(String sql) throws java.sql.SQLException {
        try{
            this.showOperation("Executando o comando sql: [" + sql + "]..."); 
            if (this.statement == null) 
            this.statement = con.createStatement(); 
            this.showOperation("Ok."); 
            return this.statement.executeUpdate(sql); 
        }catch(Exception e){ 
            throw this.makeSQLException(e, sql); 
        } 
    } 

    /** Executa uma consulta SQL */ 
    public ResultSet executeQuery(String sql) throws java.sql.SQLException {
        try{
            this.showOperation("Executando consulta: [" + sql + "]..."); 
            if (this.statement == null) 
            this.statement = con.createStatement(); 
            this.showOperation("Ok."); 
            return this.statement.executeQuery(sql); 
        }catch(Exception e){
            throw this.makeSQLException(e, sql); 
        } 
    } 
}

Desculpem o excesso de código mas foi o único jeito de deixar mais claro o meu problema.

Se alguem poder ajudar…

At+

6 Respostas

Daniel_Quirino_Olive

Uma solução: use ThreadLocal para obter a conexão com o banco de dados. http://java.sun.com/j2se/1.4.2/docs/api/java/lang/ThreadLocal.html.

B

Daniel, não entendi bem isto que vc sugeriu:

isto seria pra tratar a concorrência?
se for, eu declarando um método com synchronized não resolveria?

Daniel_Quirino_Olive

Sim, é para tentar resolver o problema de concorrência. Sincronizar o acesso ao método de fato deveria resolver, mas estou aqui me perguntando se este comportamento pode ser um bug do Commons-DBCP. De qualquer forma, use este tipo de “workaround” para resolver seu problema.

B

Daniel,

Sem querer ser chato, isto eh só uma sugestão ou você ja resolveu esse tipo de problema com isso.
Não leve a mal cara, eh porque ja passei um tempão quebrando a cabeça com isso e nada feito.

Valeu pela ajuda também…

rodolfo_dpk

bmcneto,

Considere utilizar um desenho mais tradicional, como DAOs com métodos estáticos consumindo os objetos Connection via uma Abstratc Factory. Pode parecer complicado mas no site da Sun mesmo vc pode achar referências sobre pattern DAO. Talvez seja mais fácil que ficar focando em monitores e threads…

Mas como alterar código é muito mais arriscado (vc pode criar outros bugs !!) e provavelmente inviável, considere dividir sua classe em duas : uma classe A que fornece os objetos Connection (de preferência via um método static) e outra classe B que executa as operações com o BD e consome os objetos Connection da classe A.

Acho que não daria muito trabalho e vale a pena tentar. Vc tbém pode tentar utilizar um framework que encapsula JDBC (procure “jdbc framework” no Google) ou cheque Spring Framework, que tbém contém um framework que simplifica o JDBC, porque pelo que vi do seu código é isto que vc está tentando fazer.

Boa sorte !

Boa sorte !

Daniel_Quirino_Olive

“bmcneto”:
Daniel,

Sem querer ser chato, isto eh só uma sugestão ou você ja resolveu esse tipo de problema com isso.
Não leve a mal cara, eh porque ja passei um tempão quebrando a cabeça com isso e nada feito.

Valeu pela ajuda também…

Eu costumava usar ThreadLocal com o Hibernate para que manter a associação entre uma Session e a thread da aplicação, mas nunca tentei isso com JDBC. É bem provável que funcione, uma vez que cada thread tem acesso a uma cópia exclusiva de uma variável quando se usa ThreadLocal.

Criado 15 de outubro de 2003
Ultima resposta 16 de out. de 2003
Respostas 6
Participantes 3