Rodrigo Fortes

"Só duas coisas são infinitas, o universo e a estupidez humana, mas não estou seguro sobre o primeiro"

Configurando Pool de Conexão com JPA

Aplicações pequenas podem não precisar de um pool de conexões, porém aplicações maiores, o pool pode se fazer necessário, pois a cada conexão com o banco é aberto uma conexão no início da transação e fechada ao final, isto pode tornar sua aplicação inutilizável dependendo do número de requisições.

“Mas o que faz o pool? Basicamente, mantém um certo número de conexões abertas com o banco de dados. Quando o cliente Java abre uma conexão usando o pool, ao invés de abrir uma nova conexão com o banco usando o driver JDBC, este simplesmente pega uma das conexões já aberta com o banco e a marca como alocada para aquele cliente Java.

O cliente Java então usa a conexão normalmente e faz as operações desejadas no banco. Quando o cliente fecha a conexão usando o pool, este não fecha a conexão com o banco. Ao invés disso, mantém a mesma aberta, mas a marca como disponível.

Quando o número de conexões que os clientes abrem usando o pool passa do número de conexões que o connection pool mantém abertas, o pool abre uma nova conexão com o banco de dados, a não ser que tenha atingido um número máximo de conexões reais, caso no qual seria lançada uma exceção.” (http://www.devmedia.com.br/connection-pool/5869)

Neste contexto eu tive uma certa dificuldade em configurar um pool de conexões com JPA. O cenário era um sistema REST que já estava em produção utilizando Hibernate puro e realizava o pool com C3P0 (já falaremos dele). Ao colocar as dependências e configurações do JPA o pool para de funcionar.
Como foi difícil achar a solução, vou compartilhar com vocês duas configurações de pool, uma direto no servidor Tomcat e outra através do C3P0.

Pool de Conexão no Tomcat.

Primeiramente realizamos a configuração no Tomcat através dos arquivos server.xml e contexto.xml.

Pool de conexão configurado no arquivo server.xml do Tomcat na tag através de um datasource.

 <Resource name="jdbc/TesteDB"   
        auth="Container"   
        type="javax.sql.DataSource"   
        validationInterval="30000"   
        timeBetweenEvictionRunsMillis="30000"   
        maxActive="100"   
        minIdle="10"   
        maxWait="10000"   
        initialSize="10"   
        minEvictableIdleTimeMillis="30000"   
        jmxEnabled="true"   
        jdbcInterceptors="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;  
         org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer;  
         org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer"   
        username="dev"   
        password="dev@1"   
        driverClassName="org.postgresql.Driver"   
        url="jdbc:postgresql://192.168.0.165:5432/teste_v_3_1_0"/>  

No arquivo context.xml do Tomcat, referenciar o datasource criado.

 <ResourceLink name="jdbc/TesteDB"   
        global="jdbc/TesteDB"   
        auth="Container"   
        type="javax.sql.DataSource" />  

Agora vamos para aplicação e no arquivo web.xml, referenciamos o datasource através do código abaixo.

 <resource-ref>  
   <description>DB Connection</description>  
   <res-ref-name>jdbc/TesteDB</res-ref-name>  
   <res-type>javax.sql.DataSource</res-type>  
   <res-auth>Container</res-auth>  
 </resource-ref>  

Como a aplicação está utilizando JPA, no arquivo persistence.xml fazemos referência ao datasource com a linha de código abaixo:

 <non-jta-data-source>java:/comp/env/jdbc/TesteDB</non-jta-data-source>  

Obs: deve ficar logo abaixo da tag.

Ainda no persistence, inclua apenas a propriedade de dialeto.

 <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />  

Agora a parte mais importante, e a causa de todo o trabalho para configuração, utilizar a versão 5.0.4 ou superior do hibernate-entitymanger, pois as versões inferiores possui um bug na utilização de datasource no JPA, o que causou uma certa dor de cabeça. Abaixo as dependência no arquivo pom do Maven.

 <dependency>  
             <groupId>org.hibernate</groupId>  
             <artifactId>hibernate-entitymanager</artifactId>  
             <version>5.0.4.Final</version>  
         </dependency>  
          <dependency>  
             <groupId>javax.validation</groupId>  
             <artifactId>validation-api</artifactId>  
             <version>1.0.0.GA</version>  
         </dependency>  
         <dependency>  
             <groupId>org.hibernate</groupId>  
             <artifactId>hibernate-validator</artifactId>  
             <version>5.2.2.Final</version>  
         </dependency>  
         <dependency>  
             <groupId>org.hibernate.javax.persistence</groupId>  
             <artifactId>hibernate-jpa-2.1-api</artifactId>  
             <version>1.0.0.Final</version>  
         </dependency>  

Pool de Conexão com C3P0

c3p0 é uma biblioteca fácil de usar para drivers JDBC tradicionais "enterprise-ready", meçhorando sua funcionalidade definida pela especificação JDBC3 e as extensões opcionais para JDBC2. A partir da versão 0.9.5, c3p0 apoia plenamente a especificação JDBC4.
Em particular, c3p0 fornece vários serviços úteis:
  • Uma classe para adaptar os drivers JDBC tradicionais baseados em DriverManager para o mais recente regime  de aquisição de conexões de banco de dados através do javax.sql.DataSource.
  • Pooling transparente de Conexão e PreparedStatements.
A biblioteca se esforça para acertar os detalhes:
  • DataSources c3p0 são ambos Referenciável e Serializable, e são, portanto, adequados para a ligação de uma ampla variedade de serviços de nomenclatura baseado em JNDI.
  • Declaração e ResultSets são cuidadosamente limpos quando Conexões e Demonstrações são alocadas, para evitar a exaustão em recursos quando os clientes usam a estratégia de gestão de recursos Lazy, mas comum do que apenas limpar suas conexões. 
  • A biblioteca adota a abordagem definida pela especificação JDBC 2 e 3. DataSources são escritos no estilo JavaBean, oferecendo todo o necessário e a maioria das propriedades opcionais. Todas as interfaces internas JDBC-definidos são implementadas (ConnectionPoolDataSource, PooledConnection, ConnectionEvent-generating Connections, etc.) Você pode misturar as classes c3p0 com implementações de terceiros (embora nem todos os recursos c3p0 irá trabalhar com implementações externas de ConnectionPoolDataSource).
c3p0 espera fornecer implementações de DataSource mais do que adequado para uso por aplicativos corporativos J2EE de alto volume.

Para configurar o pool com C3P0 precisamos adicionar suas dependências no pom.xml.

 <dependency>  
             <groupId>com.mchange</groupId>  
             <artifactId>mchange-commons-java</artifactId>  
             <version>0.2.10</version>  
         </dependency>  
         <dependency>  
             <groupId>c3p0</groupId>  
             <artifactId>c3p0</artifactId>  
             <version>0.9.1.2</version>  
         </dependency>  

Atualizado a dependência, basta adicionar as propriedades do C3P0 no arquivo persistence.xml.

 <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />  
             <property name="hibernate.connection.url" value="jdbc:postgresql://192.168.0.165:5432/teste_v_3_1_0" />  
             <property name="hibernate.connection.username" value="senha" />  
             <property name="hibernate.connection.driver_class" value="org.postgresql.Driver" />  
             <property name="hibernate.connection.password" value="password" />  
       <property name="hibernate.connection.provider"  
              value="org.hibernate.connection.C3P0ConnectionProvider" />  
          <property name="hibernate.c3p0.min_size" value="5" />  
           <property name="hibernate.c3p0.max_size" value="100" />  
           <property name="hibernate.c3p0.timeout" value="300" />  
           <property name="hibernate.c3p0.max_statements" value="50" />  
           <property name="hibernate.c3p0.idle_test_period" value="3000" />  
           <property name="hibernate.c3p0.min_size" value="5" />  
           <property name="hibernate.c3p0.max_size" value="100" />  
           <property name="hibernate.c3p0.timeout" value="300" />  
           <property name="hibernate.c3p0.max_statements" value="50" />  
           <property name="hibernate.c3p0.idle_test_period" value="3000" />  

Agora é só tirar o máximo de proveito do pool de conexão e ser feliz.
O projeto completo está disponível no GitHub.

Referências

http://www.mchange.com/projects/c3p0/
http://www.devmedia.com.br/connection-pool/5869