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