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.
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.
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
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) {} } }
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) {} } }