Configurar Datasources no Tomcat

Apesar de ser bem conhecido, muitas pessoas não sabem configurar ou nem sabem que existe algo muito interessante a respeito de conexão com Banco de Dados com Java Web: é o conceito de DataSources (ou Connection Pool). Utilizando este tipo de conexão, há uma otimização violenta na utilização de qualquer banco de dados. Neste post, irei descrever os benefícios de utilizar Datasources e de como utilizar tal recurso no Tomcat. É recomendado que o leitor saiba o que são conexões e drivers JDBC e como utilizá-los.

Qualquer aplicação web deve estar pronta para receber várias requisições simultâneas, e em cada uma delas normalmente se acessa um banco de dados para se obter o conteúdo da página. A cada requisição, é aberta e fechada uma conexão com o Banco, um processo que causa certa lentidão, pois muitas requisições simultâneas requerem que múltiplas conexões sejam criadas.

A tradução de Connection Pool é “piscina de conexões”, e é justamente essa a idéia que se deve ter: um local onde já existe uma ou mais conexões com o banco de dados ociosas, esperando que uma requisição seja feita.

Ta… mas qual a vantagem de usar este pool?

A vantagem é que várias requisições podem ser atendidas por um número pequeno de conexões, pois após as mesmas serem utilizadas, elas voltam para o Pool, e ficam prontas para atender uma outra requisição.

Sem contar o ganho de tempo, pois a conexão já está estabelecida: não é necessário efetuar todo o processo de login e estabelecer uma nova conexão no banco para cada solicitação.

Hmmmm… tá ficando bom! E o que eu preciso para utilizar isso?

Precisa configurar o conteiner web para que o mesmo possa gerenciar o Pool. Neste post, explicarei como fazer esta configuração no Tomcat.

Moral do Pool de Conexões

O pool nada mais é que um conjunto de conexões JDBC esperando para atenderem alguma solicitação. Sendo assim, o pool funcionará da seguinte forma:

– caso seja solicitada uma conexão e não houver nenhuma no pool, uma conexão será criada para atender esta solicitação. Enquanto ela estiver atendendo esta requisição, ficará com o status de ‘ocupada’, e após atendê-la, esta conexão voltará para o pool com o status de ‘ociosa’;

– caso seja solicitada uma conexão e todas as existentes no pool estiverem com status de ‘ocupada’ uma nova conexão será criada (respeitando o limite máximo de conexões do pool);

– caso o numero máximo de conexões for atingido e todas estiverem ocupadas, o pool irá aguardar uma conexão retornar a ficar ociosa para atender a uma requisição.

Desta forma, percebemos que o numero máximo de conexões dentro de um pool é o mesmo de requisições simultãneas que ocorrerem.

Passos para a utilização de DataSources no Tomcat:

1 – Salvar o driver de conexão com o banco de dados no diretório de libs do Tomcat ($CATALINA_HOME/lib);

2 – Configurar no Contexto da aplicação no Tomcat os seguintes dados (exemplo de conexão com o Banco POSTGRESQL):

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/exemplo" docBase="exemplo">

<!-- datasource -->
    <Resource name="jdbc/exemplo-ds"
              auth="Container"
              scope="Shareable"
              type="javax.sql.DataSource"
              username="usuario_banco"
              password="senha_banco"
              driverClassName="org.postgresql.Driver"
              url="jdbc:postgresql://localhost:5432/nome_banco"
              maxActive="100"
              maxIdle="30"
              maxWait="10000"/>
</Context>


Para quem não sabe configurar um elemento de contexto no Tomcat, uma breve ajuda de onde o mesmo pode ser definido:

a) em $CATALINA_HOME/conf/context.xml: será carregado por todas as aplicações do container;

b) em $CATALINA_HOME/conf/[enginename]/[hostname]/context.xml: será carregado por todas as aplicações do hostname especificado;

c) no diretório $CATALINA_HOME/conf/[enginename]/[hostname]/”nomedocontexto.xml”. Será carregado pela aplicação que tiver o nome do contexto igual ao nome do XML (sem a extensão);

d) SE NENHUM DOS ARQUIVOS ACIMA existir, em /META-INF/context.xml dentro da própria aplicação.

Um detalhe que não pode deixar passar despercebido é que, caso a opção D seja utilizada, o arquivo context.xml dentro do META-INF será copiado para o $CATALINA_HOME/conf/[enginename]/[hostname]/”nomedocontexto.xml”. Neste caso. ao fazer uma alteração no context.xml, deve-se entrar no diretório $CATALINA_HOME/conf/[enginename]/[hostname]/ e deletar o “nomedocontexto.xml”, caso contrário o arquivo não será atualizado (sofri alguns dias até descobrir isso!).

3 – Incluir no web.xml o recurso JNDI a ser usado:

<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">

<!-- dados do seu web.xml .... -->

    <resource-ref>
        <res-ref-name>jdbc/exemplo-ds</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <res-auth>Container</res-auth>
    </resource-ref>
</web-app>


4 – Criando uma conexão pelo Pool no código Java:

InitialContext initCtx = new InitialContext();
DataSource ds = (DataSource) initCtx.lookup( "java:/comp/env/jdbc/exemplo-ds" );
Connection con = ds.getConnection();

E é isso!

Um detalhe IMPORTANTÍSSIMO é fechar TODAS as conexões utilizadas pelo pool, pois na verdade a conexão não será “fechada”, e sim devolvida ao Pool. É como pegar um livro de uma biblioteca: ele não voltará para a prateleira sozinho: você tem que devolvê-lo. E devolver a conexão para o pool é utilizar o método close() do objeto Connection. Abaixo um exemplo de código:

Connection conn = null;
Statement stmt = null;  // Ou PreparedStatement
ResultSet rs = null;
try {
    conn = //... pega a conexão do pool ...
    stmt = conn.createStatement("select ...");
    rs = stmt.executeQuery();
    //... itera sobre o resultset e cria os objetos ...
    } catch (SQLException e) {
        //... trata os erros ...
    } finally {
        // fecha todos os recursos e devolve a conexao ao pool
        if (rs != null && !rs.isClosed() ) {
            try { rs.close(); } catch (SQLException e) { ; }
            rs = null;
        }
        if (stmt != null && !stmt.isClosed() ) {
            try { stmt.close(); } catch (SQLException e) { ; }
            stmt = null;
        }
        if (conn != null && !conn.isClosed() ) {
            try { conn.close(); } catch (SQLException e) { ; }
            conn = null;
        }
}


Bom, é isso! Em um próximo post irei explicar como funciona o uso de DataSources no JBoss.

Espero ter ajudado.

Referências:

http://tomcat.apache.org/tomcat-5.5-doc/jndi-datasource-examples-howto.html

http://tomcat.apache.org/tomcat-5.5-doc/config/context.html

Abraço!

Deixe um Comentário

19 Comentários.

  1. muito bom, nada mais a acresentar…

  2. Excelente!
    Descobri vários detalhes que eu desconhecia…
    Parabéns!

  3. Olá Hallan,
    Segui seu tutorial contudo minha aplicação não está executando no IE nem na IDE (eclipse Galileo), somente no Chrome 🙁
    Alguma idéia?!?!

    Desde já agradeço a atenção!

  4. Jeverson:

    Qual o erro que você teve?

    Se está funcionando no Chrome, então o problema não deve estar no seu código, e sim no IE/Navegador do Eclipse.

    Normalmente, quando funciona em um browser e no outro não, é por conta do cache. Tente limpar o cache e acessar no IE novamente.

    Abraço!

  5. Limpei o cache, porém o erro persiste. No IE7 ele fica somente na index.html e tentando conectar, o msmo ocorre no browser da IDE.

    Meu bean:

    package com.corejsf;

    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    import javax.naming.Context;
    import javax.naming.InitialContext;
    import javax.naming.NamingException;
    import javax.servlet.jsp.jstl.sql.Result;
    import javax.servlet.jsp.jstl.sql.ResultSupport;
    import javax.sql.DataSource;

    public class CustomerBean {
    private Connection conn;

    public void open() throws SQLException, NamingException {
    if (conn != null) return;
    Context ctx = new InitialContext();
    DataSource ds = (DataSource) ctx.lookup(“java:comp/env/jdbc/mydb”);
    conn = ds.getConnection();
    }

    public Result getAll() throws SQLException, NamingException {
    try {
    open();
    Statement stmt = conn.createStatement();
    ResultSet result = stmt.executeQuery(“SELECT * FROM Customers”);
    return ResultSupport.toResult(result);
    } finally {
    close();
    }
    }

    public void close() throws SQLException {
    if (conn == null) return;
    conn.close();
    conn = null;
    }
    }

    O web.xml da minha aplicação:

    05f_database

    Faces Servlet
    javax.faces.webapp.FacesServlet
    1

    Faces Servlet
    *.faces

    index.html
    index.htm
    index.jsp
    default.html
    default.htm
    default.jsp

    MySQL DataSource
    jdbc/mydb
    javax.sql.DataSource
    Container

    a index.jsp:

    index.html:

    Iniciando aplicação web

    Aguarde enquanto a aplicação web é iniciada!

    ${catalina_home}/conf/context.xml:


    WEB-INF/web.xml


    <!–

    –>

    <!–

    –>

    Seguindo outro tutorial, também acrescentei à tag do meu ${catalina_home}/conf/server.xml o seguinte:

    Alguma dica de onde possa estar o erro??
    Caso tenha postado indevidamente aqui, desculpe-me!

    Grato pela atenção

    Abraço!

  6. hummm….seu blog ñ aceita as tags…rs!

    Neste tópico do GUJ tem uma msg q postei sobre o assunto:
    http://www.guj.com.br/posts/list/141523.java#768777

  7. Assim:

    Estás usando JSF também. Eu recomendo você testar uma coisa de cada vez, para achar a fonte do problema. Tente substituir (comentar) os códigos de acesso ao BD por objetos criados “na hora”: assim você sabe se o problema é o acesso ao BD ou não.

    Como eu disse: se funciona do Chrome, a conexão funciona, pois ela independe de browser (roda no servidor). Já o JSF roda no browser – provável causa do problema.

    Lembro que o JSF é assim mesmo: depende do browser, do servidor (tomcat/jboss/glassfish/websphere) – cada um deles tem suas particularidades, o que pode complicar sua configuração do faces.

    Abraço!

  8. Então…estou estudando JSF pelo livro CoreJSF, venho seguindo capítulo a capítulo, sendo assim, jah testei várias aplicações JSF em meu ambiente de desenvolvimento, todas rodaram numa boa! Vou testar agora com o exemplo do jndi-datasource-examples-howto da documentação do TomCat6 e também vou instalar o FireFox pra ver qual o resultado obtido. Qlq novidade posto aki!

    Vlw pela atenção (vou ajudar a divulgar seu blog…hehe!)

    abraço

  9. Caro Hallan e d+ leitores,

    Problema resolvido…..
    O lance era nessa linha do meu index.html
    meta http-equiv=”Refresh” content=”0; index.faces”

    o correto é isso:
    meta http-equiv=”Refresh” content=”0; URL=index.faces”

    sem o URL o IE não redireciona, jah o Chrome redireciona numa boa!

    Abraço a todos!

  10. Cara, massa você ter conseguido resolver!

    Programar pra web eh assim mesmo: dias pra descobrir que um browser tem “facilidades” que outros não tem hehee!!

    Abraço e sucesso!

  11. ÊÊÊÊÊÊÊÊÊÊÊÊ, até que enfim um tutorial que funcionou!!!!!

  12. Gostei do post …
    VALEUUUU

  13. Parabéns!….muito bom seu blog.

    tenho uma pergunta quanto ao pool:

    usando o pool não há possibilidade de causar duplicidade de registro, ja que as conecções não fecham?

  14. Não há essa possibilidade, pois a conexão só volta para o Pool depois de ser utilizada e “devolvida explicitamente” pela aplicação. Em nenhum momento uma conexão será usada simultaneamente em dois lugares.

    Abraço!

  15. Thiago Moitinho

    Bem tenho uma aplicação em java . Aparentemente funcionando tudo bem. Sendo quando chego em um menu (Ex Serviço). Eu tenho opção de busca. Ai vou em editar o serviço já cadastrado e ai vejo tudo certinho. Saio sem salvar sem editar nada e vou para opção cadastrar ai ele puxa o formulario do ultima opção que eu entrei, que foi do serviço editar . Oque pode ser isso .. Ele não limpa a utima entrada … Obrigado

  16. Thiago Moitinho

    Estou rodadndo tomcat ..

    Vou em serviço pego um serviço criado . fecho e vou em novo serviço ele puxa o que eu cliquei o editar …

  17. Cara, muito bom ! Muitos detalhes que outros caras fazem parecer sombrios. Vc tem canal no YouTube? Ganhou minha seguida

  18. Gostei, salvou a pátria aqui em uma conexão que eu precisava fazer no SpagoBi. Obrigado!

  19. Neste exemplo não foi alterado o server.xml do toncat, apenas o context.xml da aplicação. Alguém sabe dizer qual o melhor/seguro caminho para desenvolver o pool, fazendo apenas na aplicação (context.xml) ou usando server.xml?

Deixe um Comentário


NOTA - Você pode usar estesHTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>