Tratamento de Conexões
Um identificador de conexão é uma representação de uma conexão física. Para utilizar um recurso backend, como um banco de dados relacional no WebSphere Application Server, você deve obter uma conexão com esse recurso. Quando o método getConnection() é chamado, uma manipulação de conexões é retornada. O identificador não é a conexão física. A conexão física é gerenciada pelo gerenciador de conexão.
Há duas configurações significantes que afetam como as manipulações de conexões são utilizadas e como se comportam. O primeiro é o res-sharing-scope, que é definido pela referência de recurso usada para procurar a DataSource ou Connection Factory. Essa propriedade diz ao gerenciador de conexão se você pode ou não compartilhar essa conexão.
- obtém uma conexão
- efetua seu trabalho
- consolida (se apropriado)
- fecha a conexão
- obtém uma conexão
- inicia uma transação global
- efetua trabalho na conexão
- consolida uma transação global
- efetua trabalho na conexão novamente
- O suporte a identificador em cache exige algum gerenciamento adicional do identificador de conexão através desses limites, o que pode causar impacto no desempenho. Por exemplo, em um aplicativo JDBC, Statements, PreparedStatements e ResultSets são fechados implicitamente após a conclusão de uma transação, mas a conexão permanece válida.
- É recomendado não armazenar em cache a conexão pelo limite da transação para conexões compartilháveis; é preferível usar o padrão obter/usar/fechar.
- O armazenamento em cache de identificadores de conexão entre os métodos de servlet está limitado a recursos JDBC e JMS (Java™ Message Service). Outros recursos não relacionais, como objetos CICS (Customer Information Control System) ou IMS, atualmente não podem ter identificadores de conexão armazenados em cache em um servlet; é necessário obter, utilizar e fechar o identificador de conexão em cada chamada de método. (Esta limitação aplica-se apenas aos servlets de encadeamento único, pois os servlets de múltiplos encadeamentos não permitem o armazenamento em cache de identificadores de conexão.)
- Não é possível transmitir uma manipulação de conexões armazenada em cache de uma
instância de um cliente de acesso a dados para outra instância do cliente. A transferência entre instâncias do cliente cria a contingência problemática de uma instância utilizando uma
manipulação de conexão referenciada por outra. Esse relacionamento pode causar problemas apenas porque o código de gerenciamento de manipulação de conexão processa as tarefas de
cada instância do cliente separadamente. Consequentemente, a manipulação de conexão
transfere o resultado em cenários de tempo de execução que acionam exceções.
Por exemplo:
- O código do aplicativo de uma instância do cliente que recebe uma manipulação transferida fecha a manipulação.
- Se a instância do cliente que retém a referência original para a manipulação tentar recuperá-la, o servidor de aplicativos emitirá uma exceção.
O segmento de código a seguir mostra o padrão de conexão armazenada em cache.
Connection conn = ds.getConnection();
ut.begin();
conn.prepareStatement("....."); // A conexão é executada no modo de transação global
...
ut.commit();
conn.prepareStatement("....."); // Conexão ainda válida, mas executada em autoCommit(True);
...
Conexões Não Compartilháveis
Algumas características de identificações de conexões recuperadas com um res-sharing-scope de não compartilhável são descritas nas próximas seções.- Os possíveis benefícios de conexões não compartilhadas
- O aplicativo sempre mantém um vínculo direto com uma conexão física (conexão gerenciada).
- A conexão sempre tem um relacionamento um a um entre o identificador da conexão e a conexão gerenciada.
- Na maioria dos casos, a conexão não fecha até que o aplicativo a feche.
- É possível utilizar um identificador de conexão não compartilhada em cache entre várias transações.
- A conexão pode ter uma vantagem de desempenho em algumas situações de identificador em cache. Como as conexões não compartilhadas não têm a sobrecarga de mover identificadores de conexão para fora de conexões gerenciadas no final da transação, há menos sobrecarga no uso de uma conexão não compartilhada em cache.
- As possíveis desvantagens de conexões não compartilhadas
- Uso ineficiente dos recursos da conexão. Por exemplo, se dentro de uma única transação você obtiver mais de uma conexão (com as mesmas propriedades) utilizando a mesma origem de dados ou connection factory (mesma resource-ref), você utilizará várias conexões físicas quando utilizar conexões não compartilháveis.
- Conexões desperdiçadas. É importante não manter a manipulação de conexões aberta (ou seja, seu aplicativo não chama o método close() por mais tempo do que a manipulação de conexões é necessária. Enquanto uma conexão não compartilhável estiver aberta, a conexão física não estará disponível para qualquer outro componente, mesmo se o aplicativo não estiver utilizando atualmente essa conexão. Diferente de uma conexão que pode ser compartilhada, uma conexão não compartilhável não é fechada no final de uma transação ou chamada de servlet.
- Considerações sobre congelamento. Dependendo de como os componentes interagem com
o banco de dados em uma transação, utilizar conexões não compartilháveis pode levar a
conflito no banco de dados. Por exemplo, em uma transação, o componente A
obtém uma conexão à origem de dados X e atualiza a tabela 1, e depois chama o componente
B. O componente B obtém outra conexão à origem de dados X, e atualiza/lê
a tabela 1 (ou, pior ainda, a mesma linha que o componente A). Em algumas circunstâncias,
dependendo do banco de dados específico, de seu esquema de travas e do nível de isolamento da transação,
pode ocorrer um congelamento.
No mesmo cenário, mas com uma conexão compartilhada, o conflito não ocorre porque todo o trabalho é feito na mesma conexão. É necessário observar que, ao gravar o código que utiliza as conexões compartilhadas, você utiliza uma estratégia que chama vários itens de trabalho para serem executados na mesma conexão, possivelmente na mesma transação. Se você decidir usar uma conexão não compartilhável, será necessário configurar a propriedade de máximo de conexões no connection factory ou na origem de dados corretamente. Pode ocorrer uma exceção para os pedidos de conexão em espera, se você exceder o número máximo de conexões e as conexões não compartilháveis não forem fechadas antes do tempo limite de espera da conexão ser excedido.
Conexões Compartilháveis
Algumas características de identificações de conexões recuperadas com um res-sharing-scope de compartilhável são descritas nas seguintes seções.- Os possíveis benefícios de conexões compartilhadas
- Em uma instância de compartilhamento de conexão, os componentes de aplicativos podem compartilhar uma conexão gerenciada em uma ou mais manipulações de conexões, dependendo de como a manipulação é recuperada e quais propriedades de conexão são utilizadas.
- Elas podem utilizar recursos com mais eficiência. As conexões compartilháveis não são
válidas fora de seu limite de compartilhamento. Por essa razão, no final de um limite de compartilhamento (como uma transação), a manipulação de conexão não é mais associada à
conexão gerenciada que estava sendo utilizada no limite de compartilhamento (isso se
aplica apenas ao utilizar o padrão de manipulação em cache). A conexão gerenciada é
retornada ao conjunto de conexões livres para reutilização. Os recursos da conexão não são
mantidos por mais tempo que o final do escopo de compartilhamento atual.
Se o padrão de manipulação em cache for utilizado, na próxima vez em que a manipulação for utilizada em um novo escopo de compartilhamento, o tempo de execução do servidor de aplicativos assegurará que a manipulação seja reassociada a uma conexão gerenciada apropriada ao escopo de compartilhamento atual e possua as mesmas propriedades com as quais a manipulação foi originalmente recuperada. Lembre-se que não é apropriado alterar propriedades em uma conexão compartilhável. Se propriedades forem alteradas, outros componentes que compartilham a mesma conexão podem encontrar um comportamento inesperado. Além disso, quando se utilizarem identificadores em cache, o valor da propriedade alterada pode não ser lembrado entre escopos de compartilhamento.
- As possíveis desvantagens de conexões compartilhadas
- O compartilhamento em um único componente (como um enterprise bean e seus objetos Java relacionados) nem sempre é suportado.
A especificação atual
permite a adaptadores de recurso a escolha de somente permitir um identificador de conexão
ativo por vez. Se um adaptador de recurso optar por implementar essa opção, o cenário a seguir resultará em uma exceção de manipulação inválida: Um componente usando conexões compartilháveis obtém uma conexão e a utiliza. Sem fechar a conexão, o componente chama uma classe do utilitário (objeto Java) que obtém um identificador de conexão com a mesma conexão gerenciada e o utiliza. Como o adaptador de recurso somente suporta um identificador ativo, o identificador da primeira conexão não é mais válido. Se o objeto utilitário retornar sem fechar a manipulação, a primeira manipulação não será válida e acionará uma exceção em qualquer tentativa de utilizá-la.Nota: Esta exceção ocorre somente ao chamar um objeto utilitário (um objeto Java).
Nem todos os adaptadores de recursos possuem essa limitação; ela ocorre em determinadas implementações. O WebSphere RRA (Relational Resource Adapter) não tem essa limitação. Nenhuma origem de dados utilizada pelo RRA possui essa limitação. Se você encontrar um adaptador de recurso com essa limitação, poderá contorná-la serializando o acesso à conexão gerenciada. Se você sempre fechar a manipulação de conexão antes de obter outra (ou fechar a manipulação antes de chamar o código que obtém outra manipulação) e antes de retornar de um método, será possível permitir que duas partes de código compartilhem a mesma conexão gerenciada. Simplesmente não é possível utilizar a conexão para ambos os eventos ao mesmo tempo.
- Tentar alterar o nível de isolamento em uma conexão baseada em JDBC compartilhável em uma transação global causa uma exceção. A maneira correta de obter conexões com diferentes níveis de isolamento de transação é configurando a referência de recurso estendido da IBM®.
- O fechamento de identificadores de conexão para conexões compartilháveis por um aplicativo NÃO é suportado e causa erros. Entretanto essa limitação pode ser evitada utilizando o RRA (Relational Resource Adapter).
- O compartilhamento em um único componente (como um enterprise bean e seus objetos Java relacionados) nem sempre é suportado.
A especificação atual
permite a adaptadores de recurso a escolha de somente permitir um identificador de conexão
ativo por vez.
Otimização de Associações de Conexões Lentas
O gerenciador de conexão Java Platform, Enterprise Edition (Java EE) Connector (J2C) implementou o suporte de identificador inteligente. Esta tecnologia ativa a alocação de uma manipulação de conexão a um aplicativo, enquanto a conexão gerenciada associada a essa manipulação de conexão é utilizada por outros aplicativos (assumindo que a conexão não está sendo utilizada pelo aplicativo original). Esse conceito faz parte da especificação Java EE Connector Architecture (JCA) 1.5. (É possível localizá-lo no documento de especificação JCA 1.5 na seção intitulada "Otimização de Associações de Conexões Lentas"). O suporte à manipulação inteligente introduz a utilização de um método no objeto ConnectionManager, o método LazyAssociatableConnectionManager(), e uma nova interface de marcador, a classe DissociatableManagedConnection. É necessário configurar o provedor do adaptador de recursos para disponibilizar essa funcionalidade no ambiente. (No caso do RRA, o próprio WebSphere Application Server é o provedor.) O snippet de código a seguir mostra como incluir o suporte à manipulação smart:package javax.resource.spi;
import javax.resource.ResourceException;
interface LazyAssociatableConnectionManager { // servidor de aplicativos
void associateConnection(
Object connection, ManagedConnectionFactory mcf,
ConnectionRequestInfo info) throws ResourceException;
}
interface DissociatableManagedConnection { // adaptador de recursos
void dissociateConnections() throws ResourceException;
}
Essa interface DissociatableManagedConnection introduz outro estado ao objeto Conexão: inativa. Uma Conexão pode estar ativa, fechada e inativa. O objeto de conexão introduz o estado inativo quando um objeto ManagedConnection correspondente está limpo. A conexão permanece inativa até o componente de aplicativo tentar reutilizá-la. Então, o adaptador de recursos chama de volta o gerenciador da conexão para reassociar a conexão a um objeto ManagedConnection ativo.