Por que eu devo ler este artigo:Este artigo é útil por apresentar o que é uma transação atômica, conceito existente na maioria dos sistemas enterprise implementados utilizando a plataforma Java EE. Para isso, serão analisadas as principais diferenças entre transações locais, globais e as formas de demarcação de cada tipo, além de entendermos como o servidor de aplicação se comporta ao identificar essas demarcações nos EJBs de uma aplicação.

Na computação, uma transação atômica representa um conjunto de uma ou mais operações efetuadas como se fossem uma unidade única e indivisível de execução. Assim, operações executadas em uma transação são todas efetivadas ou descartadas por inteiro, de forma atômica. Se ocorrer falha em pelo menos uma operação da transação, todas as operações, mesmo as que foram executadas com sucesso, são descartadas, permitindo que o estado dos dados permaneça o mesmo de antes da criação da transação.

Muitos tipos de sistemas computacionais precisam utilizar transações para que funcionem corretamente. Um caixa eletrônico, por exemplo, é um tipo de dispositivo que utiliza transações. Imagine uma transferência bancária entre duas contas, efetuada utilizando um caixa eletrônico. Uma pessoa, ao solicitar uma transferência de uma conta A para uma conta B, induz o sistema do caixa eletrônico a criar uma transação que conterá duas operações: a operação de debitar o saldo de uma conta e a operação para creditar esse saldo em outra conta.

Digamos que, hipoteticamente, a operação de debitar saldo da conta A seja efetuada com sucesso, mas a operação de creditar saldo na conta B seja negada, por restrições quaisquer, por exemplo conta inoperante. Nesse cenário, mesmo que a primeira operação tenha sido concluída com sucesso, como ela faz parte de uma transação atômica, toda a transação é abortada, e a conta corrente original A não terá seu saldo alterado. Como sabemos, esse comportamento é primordial para que o sistema funcione corretamente.

Por esse motivo, uma transação é um conceito essencial a ser utilizado em todos os sistemas que desejam integridade de dados. Com base nisso, neste artigo iremos abordar a diferença entre transações locais, globais, a demarcação de transações globais em EJBs e como o servidor de aplicação se comporta ao identificar tais demarcações, comportamento esse descrito nas especificações JTA e EJB.

Recursos transacionais e transações locais

São considerados recursos transacionais aqueles que viabilizam o suporte a transações, isto é, aqueles que possibilitam que transações sejam criadas e finalizadas corretamente. Os principais recursos transacionais empregados em aplicações corporativas — de conhecimento inerente a qualquer profissional da área de desenvolvimento de software — são os bancos de dados relacionais, utilizados para armazenar os dados da aplicação. Podemos citar como exemplos de bancos relacionais o MySQL, o SQL Server, o PostgreSQL, entre outros.

Nesses bancos de dados, podemos iniciar uma transação, executar uma série de inserções, atualizações e exclusões de dados e efetivar ou cancelar todas as operações contidas dentro dessa transação de uma só vez, de forma atômica.

Para que seja possível nos comunicarmos com esse tipo de recurso transacional na aplicação, utilizamos drivers JDBC. A especificação JDBC define as interfaces e comportamentos que todo driver JDBC deve implementar. Utilizando essa API, a aplicação é capaz de se conectar ao banco, iniciar uma transação, executar as operações necessárias, como inserir dados, por exemplo, e finalmente concluir a transação com sucesso (efetuando commit) ou com falha (efetuando rollback).

Se a aplicação utiliza apenas um banco de dados, mesmo que esse banco esteja em outro servidor, a transação criada será do tipo local. Isso porque toda transação que envolve apenas um recurso transacional — um único banco de dados relacional, por exemplo — é considerada local. Podemos verificar na Listagem 1 um exemplo de aplicação que cria uma conexão com um único recurso transacional (MySQL) e efetua a atualização de dados.

Listagem 1. Aplicação standalone – atualização de dados no banco de dados MySQL.

public class Application {
               
   public static void main(String[] args) throws Exception {
    Class.forName("com.mysql.jdbc.Driver");
    Connection conexao = DriverManager.getConnection("jdbc:mysql://localhost/test", "usuarioTeste", "12345");
    PreparedStatement pst = conexao.prepareStatement("UPDATE tb_usuario SET ativo=1");
    int totalLinhasAfetadas = pst.executeUpdate();
    conexao.close();
   }
  }
Nesse exemplo, quando a aplicação cria uma transação, executa as operações necessárias e então finaliza a transação. Todas essas operações são enviadas ao MySQL por meio do driver JDBC. O MySQL, por sua vez, torna-se responsável por gerenciar esses comandos. Perceba, nessa listagem, que não há vários recursos transacionais diferentes envolvidos, apenas um único banco MySQL. Desse modo, dizemos que a transação é local para esse recurso.

Ainda nessa listagem, observe que a transação é criada de forma implícita assim que efetuamos a atualização dos dados, portanto não foi necessária a demarcação explícita do início e fim da transação pois a especificação JDBC declara que toda nova conexão criada por um driver JDBC será configurada, por padrão, para efetuar o commit automaticamente dos comandos enviados ao banco de dados. No entanto, esse comportamento pode ser alterado, modificando a configuração de auto-commit da conexão para false. Isso indica que o driver não deverá mais efetuar commit automaticamente, apenas quando explicitamente solicitado. Nesses casos, a demarcação de início e fim da transação deve ser efetuada de forma ...

Quer ler esse conteúdo completo? Tenha acesso completo