AN style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: red; FONT-FAMILY: Verdana; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">
>
Gerenciando transações de forma 100% transparente Aprenda como criar um módulo de controle transacional robusto, reutilizável e completamente transparente à aplicação De que se trata o artigo: Gerenciamento de transações no Hibernate utilizando AspectJ. Apresentamos como criar aspectos capazes de tratarem tudo o que diz respeito ao gerenciamento de transações sem a necessidade de alteração no código responsável pelas regras de negócio. Para que serve: Prover uma forma 100% transparente de gerenciar as transações em sistemas que utilizam o Hibernate como framework de persistência. Para isso, criamos um conjunto de classes de controle transacional reutilizáveis que podem ser facilmente adicionadas a qualquer sistema Java. Em que situação o tema é útil: As transações então presentes em grande parte dos sistemas, portanto, dispor de um componente para gerenciamento de transações que seja facilmente reutilizável agiliza bastante o desenvolvimento do software. Hibernate e AspectJ: No desenvolvimento de sistemas, é bastante comum a necessidade de implementar algum tipo de gerenciamento de transações. Esse gerenciamento pode ser feito de diversas formas, porém, grande parte delas deixa o código que o utiliza acoplado, de alguma maneira, a esse serviço. Utilizando a programação orientada a aspectos (AOP), por meio da linguagem AspectJ, isso pode ser feito de maneira transparente. Com o uso de aspectos, todo o código relativo ao controle transacional fica isolado. Só é preciso, então, informar que partes do código principal (o qual contém as regras de negócios) devem ser interceptadas pelo código dos aspectos. Isso tudo é feito sem a necessidade de alterar uma linha do código principal. Utilizando esse recurso juntamente com a API de anotações de Java, é possível criar um componente reutilizável capaz de gerenciar transações em um sistema qualquer. Gerenciar transações de forma eficiente e não intrusiva é uma tarefa que ainda causa muita dor de cabeça para o desenvolvedor. Neste artigo veremos como esse problema pode ser resolvido de forma simples quando utilizamos os recursos providos pela programação orientada a aspectos. É muito comum, no desenvolvimento de sistemas, nos depararmos com requisitos que exigem uma seqüência de operações a serem realizadas de forma atômica, ou seja, onde apenas o resultado do todo faz sentido. Nesse tipo de cenário, quando qualquer operação do conjunto falha, o conjunto inteiro deve falhar. Um exemplo clássico é o da transferência entre contas de um banco, onde as operações de débito na conta origem e crédito na conta destino devem ter sucesso por completo ou falhar por completo. Um dos benefícios[1] do conceito de transação em banco de dados é exatamente o de prover essa capacidade de restaurar o estado anterior dos dados, caso ocorra alguma falha dentro do contexto transacional. Na realidade, isso é possível porque os dados não são persistidos, de fato, até que a transação seja confirmada através do comando commit, ou seja, enquanto a transação não for commitada esses dados ficam numa área de armazenamento temporária – o “log de transações” – que é visível apenas à sessão corrente, mas não aos demais usuários do BD. Para gerenciar transações no Hibernate, nos é fornecida a interface org.hibernate.Transaction com métodos como beginTransaction(), commit() e rollback(). Com a ajuda desses métodos e do mecanismo de tratamento de exceções de Java é possível demarcar o escopo transacional facilmente. Vejamos na Listagem 1 como ficaria um pseudo-código onde vários métodos são chamados num contexto transacional. Listagem 1. Pseudo-código: métodos sendo chamados num contexto transacional try { transaction.beginTransaction(); metodo1(); metodo2(); ... metodoN(); transaction.commit(); } catch (Exception e) { transaction.rollback(); } Contudo, veremos que implementar um controle transacional robusto e que não prejudique a coesão dos módulos da aplicação nem sempre é uma tarefa fácil. Neste artigo aprenderemos a implementar o gerenciamento de transações de uma forma simples, robusta, transparente e reutilizável. Para isso utilizaremos recursos da programação orientada a aspectos, através da linguagem AspectJ. Aplicação Exemplo Para que possamos praticar e validar nossa solução à medida que formos discutindo, este artigo será baseado numa aplicação exemplo que tratará do caso clássico do sistema bancário com suporte a transferência entre contas, uma vez que este deixa bem clara a importância de um controle transacional bem definido. No nosso sistema será possível efetuar operações de crédito, débito e transferência em contas bancárias. Vamos dar uma olhada no que seriam os principais requisitos da nossa aplicação: 1. O sistema deve possuir operações para crédito e débito em contas bancárias; 2. Para a operação de débito, o saldo da conta deve ser maior ou igual ao valor que se deseja debitar. Caso essa condição não seja atendida, a operação deve ser abortada e um erro deve ser gerado; 3. O sistema deve prover a funcionalidade de transferência entre contas e esta funcionalidade deve simplesmente encapsular as operações de crédito e débito; 4. Uma transferência só pode ser efetivada caso as operações de crédito na conta destino e débito na conta origem tenham sido realizadas com sucesso. Qualquer falha numa dessas operações deve cancelar a transferência. Como podemos perceber, os itens 3 e 4 deixam clara a necessidade de um controle transacional. Mas até mesmo o item 2 exige transações. Se analisarmos a fundo seria possível, por exemplo, o sistema verificar que a conta tem um saldo, aprovando então o débito, mas na fração de segundo entre esta decisão e a efetivação do débito, outro thread ou processo poderia realizar um débito concorrente. Entendidos os requisitos, vamos então definir nossas classes. A Figura 1 mostra o modelo de classes que utilizaremos. Como podemos observar nosso modelo será bem simples, composto por apenas três classes: a classe persistente Conta, a classe GerenciadorConta que encapsulará as regras do negócio e, por fim, a classe ContaDao, responsável por persistir os dados usando o Hibernate. Note também que, para simplificar, só definimos as operações necessárias para nosso estudo de caso; por exemplo, a classe ContaDao não possui métodos para inserir ou listar já que não precisaremos de tais métodos. Figura 1. Modelo de classes da aplicação exemplo A Listagem 2 mostra a definição da classe Conta. Note que estamos utilizando as annotations @Entity e @Id da JPA para fazer o mapeamento objeto-relacional. Listagem 2. Classe persistente Conta // Declaração de pacote e imports omitidos ... @Entity public class Conta implements Serializable { ...