Configurar um pool de conexões para aplicações é um requisito bastante comum, porém, a aquisição de conexões de banco de dados durante um ciclo de solicitação-resposta (request-reponse) não é uma ideia tão boa quando se deseja que a conexão com o banco leve menos tempo. Tente conectar a um banco de dados no modo de depuração e você vai experimentar um atraso significativo. O pool de conexões vem para resgatar a pré-construção de um número de conexões, com a aplicação os usando, além de ter o retorno da aplicação para opool após o uso. Agora, se você estivesse escrevendo EJBs e implantando-os em um container JEE, aí então o pooling seria fornecido pelo próprio container.

Mas imagine, por exemplo, que você tenha de usar Spring, Hibernate e Tomcat e tenha que gerenciar pools usando algo como c3p0 ou Apache DBCP.

O que você escolheria?

c3p0 é uma biblioteca “easy-to-use” usada para fornecer a capacidade de pooling de conexões. Vide seção Links para referências oficiais do projeto.

Projeto C3P0

Figura 1: Projeto C3P0

Veja na Listagem 1 um exemplo de configuração usando Spring/Hibernate comumente usado por desenvolvedores por aí.

Listagem 1: Configuração Spring/Hibernate

<bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource"
		p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}"
		p:username="${jdbc.username}" p:password="${jdbc.password}" />

	<!-- ADD PERSISTENCE SUPPORT HERE (jpa, hibernate, etc) -->

<!-- HibernateSessionFactory -->
<bean id="sessionFactory"
	class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<propertyname="dataSource">
<ref local="dataSource" />
</property>
<propertyname="configurationClass">
	<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
<propertyname="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
<propertyname="hibernateProperties">
<props>
	<propkey="hibernate.show_sql">${hibernate.show_sql}</prop>
	<propkey="hibernate.dialect">${hibernate.dialect}</prop>
	<propkey="hibernate.format_sql">${hibernate.format_sql}</prop>
	<prop key="hibernate.use_sql_comments">${hibernate.use_sql_comments}</prop>
<prop key="hibernate.auto_close_session">${hibernate.auto_close_session}</prop>
<!-- configuration pool via c3p0 -->
<propkey= "hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</prop>
<propkey="hibernate.c3p0.acquire_increment">5</prop>
<propkey="hibernate.c3p0.idle_test_period">1800</prop>
<propkey="hibernate.c3p0.max_size">600</prop>
<propkey="hibernate.c3p0.max_statements">50</prop>
<propkey="hibernate.c3p0.min_size">5</prop>
<propkey="hibernate.c3p0.timeout">1800</prop>
</props>
</property>
</bean>

O grande problema em tudo isso é que muitos desenvolvedores tentam trabalhar com o c3p0 como um adendo (complemento) ao projeto.

O código da Listagem 1, aparentemente, não funciona. Não há registros específicos do c3p0 no log da aplicação quando do start up da mesma para ter certeza de que o c3p0 foi configurado corretamente. Além disso, imediatamente após o start up, uma rápida verificada no mysql e no número de processos (um por conexão) usando “showprocesslist”; não veio nada.

Mas o que aconteceu? Aparentemente, se você estiver usando Spring e Hibernate, existem duas maneiras que você poderia usar o c3p0. Você pode deixar ou o Spring ou o Hibernate controlar o pool de conexão. Você também pode configurar ambos, mas é redundante e um desperdício de recursos e pode causar problemas com o gerenciamento de transações do Spring. A configuração acima diz que estava tentando fazer com que o Hibernate controlasse o pool, mas tê-lo controlado pelo Spring é o melhor a ser feito.

Hibernate Gerenciando o Pool

Na configuração da Listagem 1, as configurações do c3p0 estão sendo feitas na SessionFactory, o que significa que o Hibernate está sendo responsável pela gestão do pool em vez doSpring.

No caso de o Hibernate querer ser o gerenciador do pool, então a classe org.hibernate.connection.C3P0ConnectionProvider deve servir como o provedor de conexão. Esta classe não se encontra no classpath também. Portanto, se faz necessário adicionar a dependência mostrada na Listagem 2 para incluir a classe acima mencionada.

Listagem 2: Adicionando dependência Maven para classe provider do c3p0

<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>3.6.3.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-commons-annotations</artifactId>
<version>3.3.0.ga</version>
</dependency>

Isso poderá causar um aumento inicial de logs dos tipos DEBUG e INFO, mas nada tão preocupante.

Spring Gerenciando o Pool

Como mencionado anteriormente, em um ambiente controlado pelo Spring, deixe que o Spring gerencie as conexões ao longo do pool.

A classe de fonte de dados a ser utilizado na configuração acima é org.springframework.jdbc.datasource.DriverManagerDataSource, que de acordo com o javadoc não acumula conexões.

Nota: Esta classe não é um pool de conexão real, de fato ela nem sequer acumula conexões. Ela só serve como substituição simples para um pool de conexão full-blown, implementando a mesma interface padrão, mas criando novas conexões há cada chamada.

Aparentemente, esta classe implementa uma interface que exige o pool de conexão, mas na verdade também não acumula as conexões.

O próximo passo será a inclusão do próprio c3p0 (Listagem 3).

Listagem 3: Adicionando dependência do c3p0

<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
<type>jar</type>
<scope>compile</scope>
</dependency>

Então, as configurações de DataSource mudam e ficam conforme exibido na Listagem 4.

Listagem 4: Novas configurações de DataSource

<bean id="dataSource" class = "com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<propertyname="driverClass" value="${jdbc.driverClassName}" />
<propertyname="jdbcUrl" value="${jdbc.url}" />
<propertyname="user" value="${jdbc.username}" />
<propertyname="password" value="${jdbc.password}" />
<!-- these are C3P0 properties -->
<propertyname="acquireIncrement" value="${c3p0.acquireIncrement}" />
<propertyname="minPoolSize" value="${c3p0.minPoolSize}" />
<propertyname="maxPoolSize" value="${c3p0.maxPoolSize}" />
<propertyname="maxIdleTime" value="${c3p0.maxIdleTime}" />
</bean>

A classe de DataSource a ser utilizada é: com.mchange.v2.c3p0.ComboPooledDataSource

Esta classe é uma c3p0pooleddatasource. A outra diferença de antes é que propriedades do pool são definidas ao nível do DataSource em oposição à fábrica de sessão do Hibernate. O SessionFactoryBean fica bem mais simples, tal como exibido na Listagem 5:

Listagem 5: Novo SessionFactoryBean

org.hibernate.cfg.AnnotationConfiguration classpath:hibernate.cfg.xml ${hibernate.show_sql} ${hibernate.dialect} ${hibernate.format_sql} ${hibernate.use_sql_comments} ${hibernate.auto_close_session}

Concluindo

A partir dessa configuração torna-se clara a exibição da inicialização do c3p0 no Log.

Existem muitas outras configurações envolvendo os ambientes em questão assim como o c3p0. Na seção Links você poderá encontrar referências mais completas para o caso.

Links