Entendendo os atributos de transação

Nesse post vamos falar sobre um assunto pouco explorado pela maioria dos desenvolvedores: Atributos de Transação. Quando estamos desenvolvendo um serviço (seja com EJB ou Spring), podemos fazer o controle manual da transação (BTM – Bean Managed Transaction) ou deixar com que o container faça isso para nós de forma automática (CMT – Container Managed Transaction). Na maioria dos casos é usado o gerenciamento CMT e a configuração é feita de forma declarativa. É justamente para essa configuração declarativa que existem os atributos de transação. Eles definem por exemplo se seu método deve obrigatoriamente ou não ser invocado dentro de um escopo transacional.

Apenas para facilitar, sempre que for citado o termo cliente, significa que estamos falando do código “chamador”, que pode ser uma aplicação standalone, um outro EJB/Serviço Spring, etc.

Tipos de atributos de Transação

Existem 6 tipos de atributos de transação.

Required

Esse é o atributo padrão. Significa que o método a ser invocado pode ou não ser invocado dentro do escopo de uma transação, mas que obrigatoriamente ele será executado dentro de uma transação.
Se o cliente o invocar dentro de uma transação, o método será executado dentro dessa mesma transação, ficando a cargo do cliente efetuar o commit/rollback. Se o cliente não estiver dentro de uma transação, será criada uma nova transação para execução do método e, no final de sua execução, essa transação sofrerá o commit/rollback. Esse atributo é o usado na grande maioria dos casos.

RequiresNew

Significa que independentemente do cliente estar rodando ou não dentro de uma transação, uma nova transação será criada para a execução desse método e, no final de sua execução, essa transação sofrerá o commit/rollback.
Se o cliente já estiver dentro de uma transação, essa fica suspensa até o término da transação que foi criada para a execução do método. É importante notar que são 2 transações distintas, dessa forma uma não afeta a outra.

NotSupported

Significa que o método sempre será executado fora de uma transação. Se o cliente estiver dentro de uma transação, essa é suspensa até que o método execute seu código e retorne. Como o código é executado fora de uma transação, ele não afeta a transação que já estava aberta. Se o cliente não estiver no escopo de uma transação, o método será executado normalmente sem criar nenhuma transação.

Supports

Significa que o método será executado dentro ou fora de uma transação, dependendo do cliente. Se o cliente chamar o método fora de uma transação, nenhuma será criada e o método será executado fora de uma transação. Se o cliente chamar dentro de uma transação, o método será executado dentro dessa mesma transação.

Mandatory

Significa que sempre que o cliente for chamar o método, ele já deve estar em uma transação. Nesse caso, o método será executado dentro dessa mesma transação. Caso o cliente chame o método fora de uma transação, um erro será lançado e o código do método não será executado.

Never

Significa que o cliente nunca deve estar envolvido em uma transação do momento da chamada do método. Nesse caso, o método será executado normalmente sem criar nenhuma transação. Caso o cliente esteja envolvido em uma transação no momento da chamada, um erro será lançado e o código do método não será executado.

Definindo o atributo de transação

Vamos ver agora brevemente, como declarar o atributo de transação para seus serviços EJB ou Spring.

EJB

A forma mais simples de definir um atributo de transação em um EJB é através de anotações. Essa declaração pode ser feita a nível de classe, de método ou de ambos. Para a declaração, a anotação @javax.ejb.TransactionAttribute deve ser usada e são aceitos os seguintes valores (do tipo javax.ejb.TransactionAttributeType):

  • TransactionAttributeType.REQUIRED
  • TransactionAttributeType.REQUIRES_NEW
  • TransactionAttributeType.NOT_SUPPORTED
  • TransactionAttributeType.SUPPORTS
  • TransactionAttributeType.MANDATORY
  • TransactionAttributeType.NEVER

Exemplo:

import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;

@Stateless
//TransactionAttibute só é válido se TransactionManagement = TransactionManagementType.CONTAINER.
//Esse é o valor default, então essa anotação pode ser omitida
@TransactionManagement(TransactionManagementType.CONTAINER)
//Required é o default, pode-se omitir essa anotação
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class Services {

	//sem anotação assume o definido no nível da classe
	public void service1() {

	}

	//sobreescreve para esse método o valor definido a nível de classe
	@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
	public void service2() {

	}

}

Como qualquer configuração de EJB, pode-se usar XML se preferir. Maiores informações podem ser obtidas aqui.

Spring

A configuração de transação de forma declarativa no Spring é bem parecida com EJB e também pode ser feita através de anotações ou xml. Maiores detalhes podem ser encontrados aqui e aqui.

Conclusões

Apesar das configurações default de atributos de transação serem suficientes para a grande maioria dos casos, é importante conhecer quais são as opções que podem ser usadas, dessa forma o desenvolvedor pode realizar ajustes finos e necessários para que aplicação funcione corretamente de acordo com seus requisitos.


Quer aprender muito mais? Não deixe de ver meu curso Construa uma aplicação do zero com JEE 7, Java 8 e Wildfly.

Anúncios
Esta entrada foi publicada em Java EE com as etiquetas , , , , . ligação permanente.

11 respostas a Entendendo os atributos de transação

  1. ivolapuma diz:

    Olá Luciano! Este post está bem escrito e me foi muito útil para entender sobre os tipos de atributo de Transação EJB. Valeu!
    Abs,
    Ivo

  2. Rodrigo diz:

    Luciano,

    O que esses escopos interferem na conexao ? Se for Mandatory ou required ele vai aproveitar a mesma conexão aberta ? E no caso de requires_new ele vai abrir uma nova conexao ?

    Obrigado.

    Abs,

    Rodrigo

  3. cezarcruz diz:

    Post muito bom!! Obrigado!!

  4. Raul Marques diz:

    Luciano muito bom o post, bem objetivo. Estou com um problema onde minhas entidades são buscadas por um serviço ao retornar pra minha controller elas são detached, onde eu irei salvar uma entidade nova com referencia a estas entidades antes buscadas e o hibernate me fala que estão transientes e lança a famosa exception TransientObjectException.
    Estava vendo a documentação e me corrigi se eu estiver errado mas o padrão do JTA é session-per-request. Pra resolver este caso meu teria quer dar load() nas entidades de referencia dentro do escopo do serviço que salva a nova entidade.
    Sabe alguma outra solução?

    • Olá Raul,
      Não sei se entendi muito bem sua pergunta..o escopo da transação pode ser definida de forma automática no seu EJB/Spring Bean..ou você pode iniciá-la e fechá-la manualmente..enfim, pode ser feito de várias maneiras.
      Abs!

  5. Pingback: EJB: TransactionAttribute invocando métodos no mesmo EJB

  6. Patrick diz:

    Ótima explicação. No caso de não ser declarado nenhuma anotação no método, qual seria executado por padrão? Required?

Deixe uma Resposta

Preencha os seus detalhes abaixo ou clique num ícone para iniciar sessão:

Logótipo da WordPress.com

Está a comentar usando a sua conta WordPress.com Terminar Sessão / Alterar )

Imagem do Twitter

Está a comentar usando a sua conta Twitter Terminar Sessão / Alterar )

Facebook photo

Está a comentar usando a sua conta Facebook Terminar Sessão / Alterar )

Google+ photo

Está a comentar usando a sua conta Google+ Terminar Sessão / Alterar )

Connecting to %s