Artigo do tipo Tutorial
Recursos especiais neste artigo:
Conteúdo sobre boas práticas.
Gerenciando transações com Bitronix
O Bitronix Transaction Manager é um gerenciador de transação XA que implementa a JTA 1.0.1B. Iniciado em 2005, este projeto é uma alternativa para quem necessita de um gerenciador de transação que funcione independentemente de um servidor de aplicação Java EE. O BTM possibilita diversas integrações, além de ser configurado de maneira simples.
Este artigo apresenta o Bitronix Transaction Manager (ou BTM), um gerenciador de transação que implementa a JTA e é independente de um servidor de aplicação Java EE. Neste artigo será apresentado como adicionar suporte transacional em aplicações Java utilizando esta biblioteca.

Em que situação o tema é útil
Este tema é útil para desenvolvedores e projetistas que desejam conhecer uma opção de como adicionar suporte transacional distribuído em aplicações Java.

Transação é um assunto da Ciência da Computação que se discutido em cada detalhe pode facilmente gerar um livro. De uma maneira geral, podemos definir que transação é uma série de operações que devem ser executadas completamente em caso de sucesso ou serem abortadas completamente em caso de falha, não sendo tolerável um meio termo. Uma transação é caracterizada pelas propriedades ACID:

· Atomicidade: Não é aceito um resultado parcial. As modificações envolvidas na transação ou são executadas por completo ou nenhuma delas é executada;

· Consistência: Após sua conclusão, uma transação deve deixar todos os dados em um estado válido e consistente;

· Isolamento: Transações concorrentes (ou simultâneas) devem ser isoladas, ou seja, mesmo existindo concorrência, uma transação não pode interferir na execução da outra e nem podem obter resultados parciais de outras transações;

· Durabilidade: Após a conclusão da transação, todas as modificações devem ser persistidas mesmo se ocorrer uma queda de sistema, energia, etc.

Um exemplo clássico de transação é a transferência de quantias entre contas bancárias, onde apenas consideramos uma transferência como bem sucedida, quando todas as etapas que envolvem a transferência forem concluídas com êxito. Caso ocorra qualquer falha no decorrer da transferência, entende-se que todas as etapas realizadas devem ser canceladas e os estados das duas contas continuem exatamente os mesmos antes do início da transferência.

Dada a importância das transações nas aplicações, os grandes servidores de aplicação (application servers) tais como JBoss AS, Apache Geronimo, Oracle WebLogic Server, IBM WebSphere, dentre outros, oferecem suporte para o gerenciamento de transações distribuídas através da API JTA.

Mas por conta de características, muitas vezes alguns aplicativos não são adequados para execução em um servidor de aplicação. Um exemplo são os sistemas de processamento em batch. Este tipo de aplicação geralmente não é executado por um servidor de aplicação, pois este tipo de ambiente é tipicamente voltado para operações web. As aplicações batch normalmente necessitam de alto poder de processamento e são preferencialmente executadas através de outras ferramentas/frameworks. Mesmo as aplicações web, por vários motivos, podem ser executadas por um container Servlet que, em geral, não possui suporte de um gerenciador de transação.

Seja pelos motivos apresentados ou por outros, aplicações podem necessitar de suporte a transações distribuídas em suas operações, e é este o objetivo do Bitronix: oferecer suporte transacional distribuído no padrão JTA com independência dos grandes servidores de aplicação Java EE que implementam um gerenciador de transação.

Com base nisso, neste artigo iremos abordar as formas de se trabalhar com transações em aplicações Java, seus conceitos básicos e os elementos que envolvem uma transação distribuída. No decorrer do artigo, vamos conhecer o Bitronix Transaction Manager, algumas de suas configurações e preparar um ambiente que integrará esta biblioteca ao Tomcat. Ao final, iremos desenvolver uma aplicação que utilize uma transação distribuída no ambiente criado.

Tipos de transação

Na situação exemplificada de transferência de quantias entre contas bancárias e em muitas outras, necessitamos utilizar transação em aplicações para garantir a integridade das informações envolvidas. Em Java, tradicionalmente temos duas opções para gerenciar transações: local ou global (distribuída). A seguir, discutiremos sobre ambas.

Transação local

Nas transações locais, podemos gerenciar a transação para um recurso específico (por exemplo, de banco de dados). Neste tipo de transação não é levado em consideração o sucesso ou a falha de possíveis outros recursos que uma aplicação acesse, ou seja, não existe um mecanismo que tenha a habilidade de analisar o resultado do conjunto das execuções de todos os recursos para determinar o sucesso da operação. A transação é específica para cada recurso isoladamente.

Tratar a transação de recursos de forma isolada pode trazer grandes perigos para uma aplicação, pois em muitas situações um sistema depende do sucesso da execução de múltiplos recursos para efetivar sua operação.

Na Figura 1 é apresentado o exemplo mais comum de transação local, onde as transações são associadas a uma conexão JDBC (Java Database Connectivity). A aplicação, através desta conexão, pode efetivar (commit) ou rejeitar (rollback) uma transação.


Figura 1. Transação local.

Transação global (ou distribuída)

Por vários motivos, hoje em dia é muito comum às empresas possuírem sistemas que manipulam informações de origens diferentes. No exemplo da Figura 2, um aplicativo necessita fazer uma inserção (insert) em uma tabela localizada num servidor de banco de dados Apache Derby, e em seguida (dentro de uma mesma transação), necessita fazer uma atualização (update) em outra tabela, porém esta outra tabela está localizada num servidor de banco de dados PostgreSQL.

Neste exemplo, se ocorrer uma falha durante a atualização no PostgreSQL, a inserção feita inicialmente no Apache Derby também deverá ser desfeita, ou seja, a transação deve ser gerenciada em ambos os SGBDs em questão.

Figura 2. Aplicação acessando vários recursos (bancos de dados).

Como você pode notar, o cenário apresentado na Figura 2 ficou um pouco mais complexo. A transação para ser considerada bem sucedida não só depende do sucesso de execução de um banco de dados, como também de outro(s) banco(s) de dados.

Nesse cenário a transação local não seria uma solução adequada, porque ela trata cada transação de forma individual entre os recursos, isto é, todos os recursos podem ter sua transação efetivada ou rejeitada de forma independente um do outro.

...
Quer ler esse conteúdo completo? Tenha acesso completo