31.10. Pools de conexão e fontes de dado

O JDBC 2 introduziu funcionalidades de pooling de conexão padrão em uma API complementar conhecida por "JDBC 2.0 Optional Package" (também conhecida como "JDBC 2.0 Standard Extension"). Estas funcionalidades foram incorporadas ao núcleo a partir da API JDBC 3 . O driver JDBC do PostgreSQL suporta estas funcionalidades caso tenha sido compilado pelo JDK 1.3.x em combinação com o "JDBC 2.0 Optional Package" (JDBC 2), ou pelo JDK 1.4 ou posterior (JDBC 3). A maior parte dos servidores de aplicação incluem o "JDBC 2.0 Optional Package", mas também está disponível em separado na página JDBC downloads and specification da Sun.

31.10.1. Visão geral

A API JDBC fornece uma interface cliente e uma interface servidor para pooling de conexão. A interface cliente é a javax.sql.DataSource, utilizada habitualmente pelo código da aplicação para obter no pool uma conexão de banco de dados. A interface servidor é a javax.sql.ConnectionPoolDataSource, utilizada pela maioria dos servidores de aplicação para fazer a interface com o driver JDBC do PostgreSQL.

Em um ambiente de servidor de aplicação, a configuração do servidor de aplicação normalmente faz referência à implementação do ConnectionPoolDataSource do PostgreSQL, enquanto o código componente da aplicação normalmente obtém uma implementação do DataSource fornecida pelo servidor de aplicação (e não pelo PostgreSQL).

Em um ambiente sem servidor de aplicação, o PostgreSQL disponibiliza duas implementações de DataSource que a aplicação pode utilizar diretamente. Uma implementação realiza o pooling de conexão, enquanto a outra simplesmente fornece acesso às conexões de banco de dados através da interface DataSource sem qualquer pooling. Repetindo, estas implementações não devem ser utilizadas em um ambiente de servidor de aplicação, a menos que o servidor de aplicação não dê suporte à interface ConnectionPoolDataSource.

31.10.2. Servidores de aplicação: ConnectionPoolDataSource

O PostgreSQL inclui uma implementação de ConnectionPoolDataSource para o JDBC 2 e outra para o JDBC 3, conforme mostrado na Tabela 31-1 .

Tabela 31-1. Implementações de ConnectionPoolDataSource

JDBC Classe de implementação
2 org.postgresql.jdbc2.optional.ConnectionPool
3 org.postgresql.jdbc3.Jdbc3ConnectionPool

As duas implementações utilizam o mesmo esquema de configuração. O JDBC requer que o ConnectionPoolDataSource seja configurado através das propriedades JavaBean, mostradas na Tabela 31-2 , portanto existem métodos get e set para cada uma destas propriedades.

Tabela 31-2. Propriedades de configuração do ConnectionPoolDataSource

Propriedade Tipo Descrição
serverName String nome do hospedeiro do servidor de banco de dados PostgreSQL
databaseName String nome do banco de dados do PostgreSQL
portNumber int porta TCP onde o servidor de banco de dados PostgreSQL está escutando (ou 0 para utilizar a porta padrão)
user String usuário utilizado para fazer as conexões com o banco de dados
password String senha utilizada para fazer as conexões com o banco de dados
defaultAutoCommit boolean indica se as conexões devem possuir a efetivação automática habilitada ou desabilitada quando forem fornecidas por quem chama. O padrão é false, que desabilita a efetivação automática.

Diversos servidores de aplicação utilizam uma sintaxe no estilo de propriedades para configurar estas propriedades, portanto não é incomum fornecer as propriedades como um bloco de texto. Se o servidor de aplicação fornecer uma única área para especificar todas as propriedades, esta área deve ficar parecida com:

serverName=localhost
databaseName=teste
user=teste_usuário
password=teste_senha

Ou, se for utilizado ponto-e-vírgula como separador em vez de nova-linha, deve ficar parecida com:

serverName=localhost;databaseName=teste;user=teste_usuário;password=teste_senha

31.10.3. Aplicações: DataSource

O PostgreSQL inclui duas implementações de DataSource para o JDBC 2 e duas para o JDBC 3, conforme mostrado na Tabela 31-3 . As implementações de pooling na verdade não fecham a conexão quando o cliente chama o método close, em vez disso retornam a conexão para o pool de conexões disponíveis para poder ser utilizada por outros clientes. Este procedimento evita a sobrecarga de abrir e fechar conexões repetidamente, e permite um grande número de clientes compartilharem um pequeno número de conexões com o banco de dados.

A implementação de pooling de fonte de dados aqui fornecida não é a mais rica do mundo em funcionalidades. Entre outras coisa, as conexões nunca são fechadas até que o próprio pool seja fechado; não há maneira de encolher o pool. Também, as conexões solicitadas para um usuário que não seja o usuário padrão configurado não fazem parte do pool. Muitos servidores de aplicação fornecem funcionalidades de pooling mais avançadas e, em vez desta, utilizam a implementação de ConnectionPoolDataSource.

Tabela 31-3. Implementações de DataSource

JDBC Pooling Classe de implementação
2 Não org.postgresql.jdbc2.optional.SimpleDataSource
2 Sim org.postgresql.jdbc2.optional.PoolingDataSource
3 Não org.postgresql.jdbc3.Jdbc3SimpleDataSource
3 Sim org.postgresql.jdbc3.Jdbc3PoolingDataSource

Todas as implementações utilizam o mesmo esquema de configuração. O JDBC requer que o DataSource seja configurado através das propriedades de JavaBean, conforme mostrado na Tabela 31-4 , portanto existem métodos get e set para cada uma destas propriedades.

Tabela 31-4. Propriedades de configuração do DataSource

Propriedade Tipo Descrição
serverName String nome do hospedeiro do servidor de banco de dados PostgreSQL
databaseName String nome do banco de dados do PostgreSQL
portNumber int porta TCP onde o servidor de banco de dados PostgreSQL está escutando (ou 0 para utilizar a porta padrão)
user String usuário utilizado para fazer as conexões com o banco de dados
password String senha utilizada para fazer as conexões com o banco de dados

As implementações de pooling requerem algumas propriedades de configuração adicionais, conforme mostrado na Tabela 31-5 .

Tabela 31-5. Propriedades adicionais de configuração de pooling de DataSource

Propriedade Tipo Descrição
dataSourceName String Todo pooling de DataSource deve possuir um nome único.
initialConnections int O número de conexões de banco de dados a serem criadas quando o pool é inicializado.
maxConnections int O número máximo permitido de conexões de banco de dados abertas. Quando são solicitadas mais conexões, quem chama aguarda até que uma conexão retorne para o pool.

O Exemplo 31-9 mostra um código de aplicação que utiliza um pooling de DataSource.

Exemplo 31-9. Exemplo de código de DataSource

O código para inicializar o pooling de DataSource deve se parecer com:

Jdbc3PoolingDataSource source = new Jdbc3PoolingDataSource();
source.setDataSourceName("Uma fonte de dados");
source.setServerName("localhost");
source.setDatabaseName("teste");
source.setUser("teste_usuario");
source.setPassword("teste_senha");
source.setMaxConnections(10);

O código para utilizar uma conexão do pool deve ficar parecido com o mostrado abaixo. Deve ser observado que é crítico fechar as conexões, senão as conexões do pool serão "esvaziadas" e, possivelmente, todos os clientes serão bloqueados.

Connection conn = null;
try {
    conn = source.getConnection();
    // utilizar a conexão
} catch (SQLException e) {
    // registrar o erro
} finally {
    if (conn != null) {
        try { conn.close(); } catch (SQLException e) {}
    }
}

31.10.4. Fontes de dados e JNDI

Todas as implementações de ConnectionPoolDataSource e DataSource podem ser armazenadas no JNDI. No caso das implementações sem pooling, uma nova instância é criada toda vez que o objeto é trazido do JNDI, com as mesmas definições da instância que foi armazenada. Para as implementações com pooling, a mesma instância é trazida se estiver disponível (por exemplo, não for uma JVM diferente trazendo o pool do JNDI), senão é criada uma nova instância com as mesmas definições.

Em um ambiente de servidor de aplicação, normalmente a instância DataSource do servidor de aplicação é armazenada no JNDI, e não na na implementação do ConnectionPoolDataSource do PostgreSQL.

Em um ambiente de servidor de aplicação, a aplicação pode armazenar o DataSource no JNDI para não ter que fazer uma referência ao DataSource disponível para todos os componentes da aplicação que possam precisar utilizá-lo. Um exemplo é mostrado no Exemplo 31-10 .

Exemplo 31-10. Exemplo de código de DataSource JNDI

O código da aplicação para inicializar o pooling do DataSource e adicioná-lo ao JNDI deve ficar parecido com:

Jdbc3PoolingDataSource source = new Jdbc3PoolingDataSource();
source.setDataSourceName("Uma fonte de dados");
source.setServerName("localhost");
source.setDatabaseName("teste");
source.setUser("teste_usuario");
source.setPassword("teste_senha");
source.setMaxConnections(10);
new InitialContext().rebind("DataSource", source);

O código para utilizar uma conexão do pool deve ficar parecido com:

Connection conn = null;
try {
    DataSource source = (DataSource)new InitialContext().lookup("DataSource");
    conn = source.getConnection();
    // utilizar a conexão
} catch (SQLException e) {
    // registrar o erro
} catch (NamingException e) {
    // DataSource não foi encontrada no JNDI
} finally {
    if (conn != null) {
        try { conn.close(); } catch (SQLException e) {}
    }
}

SourceForge.net Logo