Gerenciando transações com EJB

Quando desenvolvemos um serviço para atender aos clientes internos e externos de uma aplicação, é muito comum controlar as transações do serviço de forma manual, por meio do processo BMT (Bean Management Transaction), ou simplesmente delegando o controle transacional para o container de execução da aplicação, técnica esta conhecida como CMT (Container Management Transation). Na maior parte das aplicações, os desenvolvedores optam por trabalhar com o conceito de CMT, deixando que o container gerencie o processo de commit e rollback das transações.

Ainda que este controle seja delegado para o container, é possível passar certas instruções comportamentais relacionadas à propagação das transações nos métodos e/ou classes elegidas como transacionais. Além de abordar os conceitos básicos dos tipos de propagação de uma transação, será apresentado ao término deste post um exemplo prático de como declarar e instruir a propagação das transações numa classe de serviço desenvolvida com Enterprise Java Bean – EJB.

Existem seis tipos de transação:

  • Required
  • RequiredNew
  • Mandatory
  • Supports
  • NotSuported
  • Never.

Required

Pode ser invocado pelo cliente dentro ou fora de um contexto transacional, mas deve sempre ser executada dentro de uma transação. Caso seja invocada pelo cliente dentro de um método que possua uma transação ativa, esta transação é aproveitada e o commit e rollback ficam sob responsabilidade do cliente chamador. Caso seja invocada fora do contexto transacional, uma nova transação é criada e o commit e rollback é efetuado pelo container.

RequiredNew

Pode ser invocado pelo cliente dentro ou fora de um contexto transacional. Caso seja chamada fora do contexto transacional, uma nova transação é criada e o método executado. Porém, se for invocada dentro de um contexto que possua uma transação ativa, esta transação é suspensa temporariamente, uma nova transação é criada e executada, e somente após o término da nova transação criada a transação anterior é completada. Por se tratar de duas transações distintas, uma não interfere na outra.

Mandatory

Faz com que seja obrigatório a invocação dentro de um contexto transacional, aproveitando a transação existente. Caso não seja invocada dentro de uma transação, é lançada a exceção javax.ejb.EJBTransactionException.

Supports

Pode ser invocado dentro ou fora do contexto transacional. Se for invocado dentro do contexto, a transação é aproveitada e segue o fluxo de execução do commit/rollback. Porém, se for invocado fora do contexto, nenhuma transação é criada e a tarefa executa normalmente.

NotSupported

Pode ser invocado dentro ou fora do contexto transacional, mas se for invocado dentro de uma transação, esta por sua vez será suspensa temporariamente para a execução do método e somente ao término do mesmo o fluxo de commit/rollback será executado. Caso seja invocado fora da transação, o método é executado normalmente.

Never

Deve ser invocado exclusivamente fora de uma transação, caso contrário é lançada a exceção javax.ejb.EJBException. Caso contrário, a tarefa é executada normalmente.

Implementando transações com Enterprise Java Beans – EJB

O controle de transações com EJBs pode ser feito em nível de classe, método ou ambos. Para isto, é necessário declarar que o controle das transações será feito pelo container – CMT, por meio da anotação @javax.ejb.TransactionManagement. Esta anotação recebe como argumento um enum do tipo javax.ejb.TransactionManagementType.

Agora que especificamos que a classe TesteService terá suas transações gerenciadas pelo container, podemos definir os atributos de transação na classe, métodos ou ambos. Esta declaração pode ser feita por meio da anotação @javax.ejb.TransactionAttribute, que recebe como argumento um enum contendo o tipo de propagação da transação, representado por javax.ejb.TransactionAttributeType.

Definiremos que as transações relacionadas à classe TesteService, inicialmente deverão ser realizadas num contexto transacional compartilhado ou independente.

Neste momento, todos os métodos da classe TesteService poderão ser invocados dentro ou fora do contexto transacional, mas o container garantirá que ele sempre seja executado numa transação. No entanto, podemos mudar o comportamento do atributo da transação em métodos específicos, por exemplo, geralmente não se utiliza transações para consultas simples. Desta forma, podemos definir um método de consulta que suporta ser executado dentro de uma transação, mas que pode ser perfeitamente executado fora da mesma.

Até a próxima!

Written by Raphael Oliveira Neves
Engenheiro de software, evangelista de novas tecnologias e apaixonado por arquitetura e desenvolvimento de software utilizando Java.