Tuesday, January 16, 2007

Controle Transacional utilizando EJB 3.0

Olá pessoal, demorei um pouco para postar .. sabem como é o final do ano. Muita festa, muita cerveja, e pouco trabalho. ;)

Este tópico vai ser um pouco diferente dos outros, vou abordar um pouco da teoria sobre transações. Uma transação é basicamente um conjunto de operações executadas em um ambiente transacional como por exemplo: Gravação de Dados em um Banco de Dados ou Envio de Mensagens utilizando-se providers JMS, etc.

Segundo a própria especificação Enterprise JavaBeans 3.0 o suporte a transações é uma das features chave do JEE. O objetivo principal de utilizar transações é possibilitar diminuir a complexidade no desenvolvimento de softwares de grande porte.

A especificação EJB 3.0 permite uma transação possa envolver dois ou mais ambientes transacionados utilizando-se um ou mais SessionBeans ou Message Driven Beans.

As figuras abaixo demostram alguns cenários possiveis:

1. Atualizar multiplos bancos de dados/MDBs em um ou Session Bean.
2. Atualizar multiplos bancos de dados/MDBs em mais de um Session Bean.
3. Atualizar multiplos bancos de dados/MDBs em mais de um EJB Container.

A idéia básica é evitar problemas com inconsistencia de dados. Uma transação deve ser necessáriamente completada por inteiro ou caso aconteça algum erro todas as alterações devem ser desfeitas.

Você pode optar por duas formas de controle transacional, Bean Managed Transactional ou Container Managed Transactional. O primeiro caso você faz o controle na "unha", ou seja, você informa no código onde quer iniciar uma transação, onde quer terminar, no segundo caso, o próprio container controla quando uma transação deve ser aberta ou fechada.

Exemplo de parte do código de um Session Bean com Bean Managed Transactional:

@Stateless
@TransactionManagement(BEAN)
public class MySessionBean implements MySession {
@Resource javax.transaction.UserTransaction ut;
@Resource javax.sql.DataSource database1;
@Resource javax.sql.DataSource database2;
...

ut.begin();
stmt1.executeQuery(...);
stmt1.executeUpdate(...);
stmt2.executeQuery(...);
stmt2.executeUpdate(...);
stmt1.executeUpdate(...);
stmt2.executeUpdate(...);
ut.commit();

...

Lembre-se que você pode utilizar tanto Stateless Session Beans como Stateful Session Beans para fazer transações, a diferença básica é que em um Stateless você deve fechar a transação antes do business método retornar e no Statefull você pode mas não é obrigado. Neste caso pode-se chamar um método do cliente que inicia a transação, chamar diversos métodos que utilizem a mesma transação e depois chamar um método que fecha a transação (Isso porque o Stateful Session Bean mantem estado. O caso 1 é um exemplo onde pode-se utilizar Bean Managed Transactional.

Os casos que envovam mais de um Session Bean Caso 2 e Caso 3 são casos clássicos de uso de Container Managed Transactional. Para você poder especificar como o container deverá tratar a execução de uma transação envolvendo mais de um Bean você deve utilizar as anotações de tipo de Managed Transaction que são as seguintes:

Mandatory: Só pode ser chamado a partir de um Bean com transação, caso contrário dispara uma Exception.

Required: Se existe transação no Bean anterior o container usa a transação, se não existir cria uma nova, essa nova transação é passada para novos Beans que possam ser chamados a partir do Bean marcado como Required.

Requires_new: Sempre cria uma nova transação, essa transação é finalizada no fim do método, ou seja, em todos os casos é apenas utilizada dentro do Bean marcado como Requires_New.

Suports: Se existir transação utiliza, se não existir ignora.

Not_Supported: Se você chama um Session Bean marcado como Not_Supported a partir de um Bean com uma transação ativa o container simplesmente ignora a transação.

Never: Só pode ser chamado a partir de um Bean sem transação, caso contrário dispara uma Exception.

Abaixo o exemplo de um Session Bean utilizando Managed Transactional:

@Stateless public class MySessionBean implements MySession {
...
@TransactionAttribute(REQUIRED)

public void someMethod(...) {
java.sql.Connection con1;
...
stmt1.executeQuery(...);
stmt1.executeUpdate(...);

...

Note que não deve-se declarar inicio de transação, nem fim.

Outra informação importante sobre transações é que qualquer serviço que seja compativel com a especificação JTA (Java Transactional API) pode ser utilizado nas transações. Os mais comuns e citados acima são Banco de Dados e Sistemas de Mensageria (JMS), mas isso não impede por exemplo de existir outros tipos de serviços como um sistema de email que armazene a msg e só envie realmente quando a transação acabar (Apesar de ficar estranho você controlar a chegada dele no cliente pois email é assincrono, isso deixaria a transação aberta por muito tempo. Mas enfim, é só um exemplo de serviço conhecido rs).

É isso ai.

[]s a todos

0 comments: