Duvida cruel com pool de conexões

4 respostas
J

Ola amigos estou com um problema em relação ao pool de conexões. Antes utilizava apenas a abertura e fechamento de conexões JDBC normais. Porém senti a necessidade de incrementar um pouco mais a minha apliacação para aumentar a performance. Resolvi implementar um pool de conexões. Contudo acho que alguma coisa no meu modelo de pool está no local errado, pois vira e mexe as minhas páginas travam e não conseguem mais consultar o banco, gostaria de saber se alguém poderia me dar uma maneira de acabar com esse problema, vou descrever o meu modelo.

Criei um bean para criar o pool de conexões:
É o seguinte:

PersistenciaBDPool.java

package objetos;

import org.apache.commons.dbcp.ConnectionFactory;
import org.apache.commons.dbcp.DriverManagerConnectionFactory;
import org.apache.commons.dbcp.PoolableConnectionFactory;
import org.apache.commons.dbcp.PoolingDataSource;
import org.apache.commons.pool.ObjectPool;
import org.apache.commons.pool.impl.GenericObjectPool;


public class PersistenciaBDPool {

    //Driver do fabricante de banco de dados (MySql)
	private static String drv = "org.gjt.mm.mysql.Driver";
	
	//Localização do host da base de dados
	private static String url = "jdbc:mysql://localhost:3306/dbintranet";
	
	//Usuário e Senha de conexão com o banco
	private static String user = "root";
	private static String password = "";

    private static PoolingDataSource dataSource;
    
    private static boolean registroOk = false;
    
	/**
	 * Método que registra o banco de dados em uso, utilizando os atributos da classe
	 * e utiliza a API dbcp commons da jakarta apache para implementar o pool de 
	 * conexões do banco de dados
	 */
	public static void registrarPoolDoBanco() {
	    
		try {
			Class.forName(drv);
		} catch (ClassNotFoundException e) {
			System.err.print(
				"Erro ao carregar o driver do banco.\nContacte o administrador do sistema.");
			e.printStackTrace();
		}
		
		ObjectPool connectionPool = new GenericObjectPool(null);
		ConnectionFactory connectionFactory = new DriverManagerConnectionFactory(url,null);
		PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(connectionFactory,connectionPool,null,null,false,true);
		dataSource = new PoolingDataSource(connectionPool);
		registroOk = true;
	}
	
    public static PoolingDataSource getDataSource() {
        return dataSource;
    }
    public static void setDrv(String drv) {
        PersistenciaBDPool.drv = drv;
    }
    public static void setPassword(String password) {
        PersistenciaBDPool.password = password;
    }
    public static void setUrl(String url) {
        PersistenciaBDPool.url = url;
    }
    public static void setUser(String user) {
        PersistenciaBDPool.user = user;
    }
    public static boolean isRegistroOk() {
        return registroOk;
    }
    public static void main(String[] args) {
    }

}

Toda vez que o usuário vai fazer alguma ação, cadastrar, pesquisar, alterar, chamo o método dentro da classe correspondente e lá verifico se o pool já foi carregado na memória, caso tenha sido utilizo os elementos JDBC normais (ResultSet e Statement) e realizo as operações, caso contrário mando carregar o pool de conexões pelo método visto acima (registrarPoolDoBanco()). Segue abaixo um exemplo com a classe Noticia.java. Aonde para visualizar uma noticia utilizo o metodo visualizar(). A classe com os elementos JDBC que trabalham com o pool e a classe exemplo (Noticia.java) seguem abaixo:

classe PersistenciaBD.java

package objetos;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class PersistenciaBD {

	//Objetos de manipulação da base de dados. (Connection, Statement e ResultSet)
	private Connection con;
	private Statement stmt;
	private ResultSet rs;
	
	/**
	 * Realiza a conexão com o banco
	 * @throws SQLException
	 */
	public void fabricarConexao() throws SQLException {
        //Verifica se o pool de conexões já está carregado na memória.
	    //Caso não esteja ele registra o pool para obter as conexões.
	    if(!PersistenciaBDPool.isRegistroOk()) {
            PersistenciaBDPool.registrarPoolDoBanco();
        }
        
	    //Obtém uma conexão do pool
        con = PersistenciaBDPool.getDataSource().getConnection();
        stmt = con.createStatement();
        
    }
	
	/**
	 * Finaliza a conexão com o banco
	 * Devolvendo ao pool a conexão solicitada anteriormente
	 */
	public void destruirConexao() throws SQLException {

	    try {

	        //Operações a serem realizadas antes de fechar os elementos
	        //da conexão

		} finally {
			try { rs.close(); } catch(Exception e) {}
			try { stmt.close(); } catch(Exception e) {}
			try { con.close(); } catch(Exception e) {}
		}
	}


    public Connection getCon() {
        return con;
    }
    public ResultSet getRs() {
        return rs;
    }
    public Statement getStmt() {
        return stmt;
    }
	public static void main(String[] args) {
	}
}

classe Noticia.java

package objetos;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.ArrayList;

public class Noticia {
    
    //Atributos da classe notícia
    private String titulo, subTitulo, fonte, 
    			   conteudo, dataNoticia, imagem;

    private int cod,capa;
    /**
     * Retorna um objeto da classe Noticia, para ser visualizado.
     * O objeto retornado é selecionado de acordo com o parametro cod
     * @param cod utilizado para localizar o registro na base de dados
     * @return um objeto da classe Noticia para ser visualizado
     */
    public void visualizar(int cod) {
	    
        boolean retorno = true;
        PersistenciaBD persistenciaBD = new PersistenciaBD();
        Noticia noticia = new Noticia();
        
        try {
            
            persistenciaBD.fabricarConexao();
			
		    Statement stmt = persistenciaBD.getStmt();
			ResultSet rs = persistenciaBD.getRs();
			
            rs = stmt.executeQuery("select * from Noticia where cod = " + cod);

            if(rs.next()) {
                this.cod = rs.getInt("cod");
                titulo = rs.getString("titulo");
                subTitulo = rs.getString("subtitulo");
                conteudo = rs.getString("conteudo");
                dataNoticia = new SimpleDateFormat("dd/MM/yy").format(rs
                        .getDate("dataNoticia"));
                imagem = rs.getString("imagem");
                capa = rs.getInt("capa");
                fonte = rs.getString("fonte");
            }
            
            persistenciaBD.destruirConexao();
           
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

Se alguém souber de algum motivo os quais podem estar prejudicando o bom funcionamento da aplicação estou a aguardar. Talvez a lógica utilizada no modelo não seja a melhor, estou aguardando sugestões. Um grande abraço a todos.!

PS: O POOL QUE ESTOU UTILIZANDO É O commons/dbcp da JAKARTA.

Um grande abraço a todos.

4 Respostas

fcanjos

Provavelmente vc está esquecendo de fechar alguma conexao.
Além disso, seria mais aconselhável colocar o método que devolve a conexão para o pool dentro de um finally.

try
{
.
.
.
}catch(Exception e)
{
.
.
.
}
finally
{
   persistenciaBD.destruirConexao();
}

Outra coisa, na minha opiniao fica mais fácil utilizar o dbcp como o jndi como mostrado aqui http://jakarta.apache.org/tomcat/tomcat-5.0-doc/jndi-datasource-examples-howto.html
talvez a tag

<parameter>
              <name>removeAbandoned</name>
              <value>true</value>
            </parameter>

possa te ajudar

J

REALMENTE AMIGO, tinha um método em que a conexão não estava sendo devolvida ao pool, e com isso quando atualizava a página que utilizava esse método algumas vezes, ela deixava de responder. Resolvi isso e ficou OK, a aplicação ficou com uma performance bem melhor. Vou dar uma olhada no modelo JNDI posteriormente… Quanto ao finally no meu caso não convém porque o método destruirConexao() lança uma exceção, e não é uma boa prática disparar possíveis exceções dentro da clausula finally… :slight_smile: Valeu pela atenção.

fcanjos

ola!!
Só pra complementar, fique atento ao fato de que se o seu método visualizar disparar uma exceção antes da chamada do persistenciaBD.destruirConexao(); , a conexão não será devolvida ao pool e o problema pode voltar a acontecer.
Descuple minha ignorância, mas por que não é boa prática disparar “possíveis” exceções dentro da clausula finally?
Falow!!

Focao

Achei interessante essa implementação

mas já tentou usar esses carinha ?

import org.apache.commons.pool.KeyedObjectPool;

import org.apache.commons.pool.KeyedPoolableObjectFactory;

import org.apache.commons.pool.impl.GenericKeyedObjectPool;

Já usei certa vez !
O conceito correto do poll usando getInstance

dá trampo mas fica elegante com a facilidade do clear

dá uma zoiada

package projeto.util;

import org.apache.commons.pool.KeyedObjectPool;

import org.apache.commons.pool.KeyedPoolableObjectFactory;

import org.apache.commons.pool.impl.GenericKeyedObjectPool;

import projeto.util.exceptions.MyLoginException;
import projeto.util.exceptions.ConnectionDownException;

/**

  • @author cpsantos

  • To change the template for this generated type comment go to

  • Window>Preferences>Java>Code Generation>Code and Comments
    */
    public class MyConnectionPool implements KeyedPoolableObjectFactory {

    /* (non-Javadoc)

    • @see org.apache.commons.pool.KeyedPoolableObjectFactory#makeObject(java.lang.Object)
      */
    private KeyedObjectPool myPool;
    
    public void backToPool(MyConnectionVO data, MyConnection con) {
    
    try {
    
    myPool.returnObject(data, con);
    
    } catch (Exception e) {
    
     	e.printStackTrace();
     }
    
    }
    
    public void destroyPool() {
    
    myPool = new GenericKeyedObjectPool(this);
    
    }
    
    public void removeUserPool(MyConnectionVO data)  {
    
    try {
    
    myPool.clear(data);
    
    } catch (UnsupportedOperationException e) {
    
    // TODO Auto-generated catch block
    
    e.printStackTrace();
    
    } catch (Exception e) {
    
    // TODO Auto-generated catch block
    
    e.printStackTrace();
    
    }
    
    }
    
    public MyConnection getConnection(MyConnectionVO data)
    
    throws MyLoginException, ConnectionDownException {
    
    try {
    
    MyConnection appCon =
    
    (MyConnection) myPool.borrowObject(data);
    
    if (appCon == null
     		|| (appCon != null
     			&& (!appCon.getSocket().isConnected()
     				|| appCon.getSocket().isClosed()))) {
     		myPool.clear(data);
     		throw new ConnectionDownException();
     	} else
     		return appCon;
    
     } catch (MyLoginException e) {
     	throw e;
    
     } catch (Exception e) {
    
     	e.printStackTrace();
     }
     return null;
    

    }

    public MyConnectionPool() {
    
    myPool = new GenericKeyedObjectPool(this);
    
    }
    
    public Object makeObject(Object arg0) throws MyLoginException {
    
    if (arg0 != null) {
    
    MyConnectionVO conData = (MyConnectionVO) arg0;
     	return MyConnection.getInstance(
     		conData.getServer(),
     		conData.getSistema(),
     		conData.getOperacao(),
     		conData.getUsuario(),
     		conData.getSenha());
     }
     return null;
    

    }
    /* (non-Javadoc)

    • @see org.apache.commons.pool.KeyedPoolableObjectFactory#validateObject(java.lang.Object, java.lang.Object)
      
      */
      
      public boolean validateObject(Object arg0, Object arg1) {
      
      return false;
      
      }
      
      /* (non-Javadoc)
      
    • @see org.apache.commons.pool.KeyedPoolableObjectFactory#activateObject(java.lang.Object, java.lang.Object)
      
      */
      
      public void activateObject(Object arg0, Object arg1) throws Exception {
      

    }
    /* (non-Javadoc)

    • @see org.apache.commons.pool.KeyedPoolableObjectFactory#passivateObject(java.lang.Object, java.lang.Object)
      */
      public void passivateObject(Object arg0, Object arg1) throws Exception {

    }
    /* (non-Javadoc)

    • @see org.apache.commons.pool.KeyedPoolableObjectFactory#destroyObject(java.lang.Object, java.lang.Object)
      */
      public void destroyObject(Object arg0, Object arg1) throws Exception {
      MyConnection con = (MyConnection) arg1;
      con.close();

    }

}

abçs

Criado 8 de março de 2005
Ultima resposta 9 de mar. de 2005
Respostas 4
Participantes 3