Gerenciamento de transação pela Application Server (Wildfly)

71 views
Skip to first unread message

Fabrício Cabral

unread,
Feb 27, 2015, 9:21:34 AM2/27/15
to ce...@googlegroups.com
Olá todos!

Estou desenvolvendo uma aplicação web (wildfly + vraptor) e gostaria de ter
um método com suporte a transação. Para isto, preferi deixar o AS cuidar do
gerenciamento de transações. Assim, suponha que eu tenha uma classe:

public class UsuarioDao {
    @PersistentContext
     private EntityManager em;
  
     // Aqui vai o resto da classe
}

E tenho uma classe ServicoUsuario:

@Stateful
public class ServicoUsuario {
    @Inject
    private UsuarioDao dao;
    
    public criaUsuario(String nome, String password) {
         dao.adiciona(new Usuario(nome, password));
    }
}

Então:

1) Basta esta anotação @Stateful para que o método criaUsuario()
seja controlado por uma transação, isto é, fico livre de ter que fazer
um begin() e um commit() do Hibernate para fazer a transação?

2) Todos os métodos públicos da classe ServicoUsuario também serão
controlados por uma transação?

3) É possível ter algum método público desta classe que não seja controlado
pela transação?

4) Se eu não colocar a anotação @Stateful ou @Stateless, por padrão, a classe
NÃO é gerenciada por uma transação?


Agradeço a atenção!

-- 
--fx

Paulo Jr.

unread,
Feb 27, 2015, 9:37:06 AM2/27/15
to CEJUG
E ai Fabrício,

Bacana a questão. Lembra que @Stateless e @Statefull são annotations que tornam a classe um EJB, e como EJB, além de transação, você ainda tem serialização, remotabilidade, mensageria e várias outras coisas que pode fazer com essa classe por ela ser um EJB. Porém, a maioria das vezes, não precisamos nem da metade disso, e podemos usar simplesmente @Named para usar o básico que é injeção de dependencia. Aliás, com VRaptor, nem o @Named não é necessário.

Sobre transação especificamente, se você está em um container JavaEE 7 como Wildfly por exemplo, basta anotar a classe ou método com @Transactional, que todos os métodos públicos terão transação por default.

1) Correto, fica livre, mas lembre-se que alguém fará pra você. E para fazer rollback, como você fará? Pesquise um pouco sobre isso, pois é importante entender o que acontece quando não fazemos nada.

2) Exato, todos terão transação.

3) Sim, você pode usar @TransactionalAttribute e setar uma propriedade que não lembro qual é para NEVER ou SUPPORTS, Never realmente nunca poderá ter transação e gera uma exception se tiver transação em algum método que o chamou, SUPPORTS não cria transação, e o método é executado sem transação se previamente não existir nenhuma.

4) Correto, não será gerenciada, mas pode usar apenas @Transactional como já citei.

Espero ter ajudado... abraço.







--
Você recebeu essa mensagem porque está inscrito no grupo "CEJUG" dos Grupos do Google.
Para cancelar inscrição nesse grupo e parar de receber e-mails dele, envie um e-mail para cejug+un...@googlegroups.com.
Para postar nesse grupo, envie um e-mail para ce...@googlegroups.com.
Acesse esse grupo em http://groups.google.com/group/cejug.
Para mais opções, acesse https://groups.google.com/d/optout.



--
Paulo Alves Junior
Twitter: @paulojribp
Github: http://github.com/paulojribp
Instrutor - Caelum | Ensino e Inovação
Hurraa - OpenSource project to resource management

Rafael Ponte

unread,
Feb 27, 2015, 9:55:05 AM2/27/15
to ce...@googlegroups.com
Olá,

O que o Paulo comentou está correto!

Mas só para resumir em poucas linhas: Desde do JEE6 todo EJB possui controle transacional automáticos em todos os métodos públicos. Se quiser mudar isso, você pode usar a anotação @TransacionalAttribute no JEE6 ou @Transaciontal no JEE7 (ou JEE8, não me recordo agora!).

Como o Paulo comentou, é melhor entender bem como funciona o controle transacional, como rollback em casos de exceções, timeout, propagações etc.

Só lembre de tomar cuidado com as atualizações indevidas pela JPA ou Hibernate.

Um abraço!

Rafael Ponte
TriadWorks | Formação Java
http://cursos.triadworks.com.br

Paulo Jr.

unread,
Feb 27, 2015, 11:21:43 AM2/27/15
to CEJUG
Mas só para resumir em poucas linhas: Desde do JEE6 todo EJB possui controle transacional automáticos em todos os métodos públicos. Se quiser mudar isso, você pode usar a anotação @TransacionalAttribute no JEE6 ou @Transaciontal no JEE7 (ou JEE8, não me recordo agora!).

Pois é, fiz uma salada com isso aí.. Você está no Wildfly então é só @Transactional mesmo. Para métodos e classes. Ah, e é JavaEE7 Ponte, o 8 ta no forno ainda hehe

Abraço.


Rafael Ponte

unread,
Feb 27, 2015, 11:26:38 AM2/27/15
to ce...@googlegroups.com
Massa, Paulo!

É que não lembrava se o @Transactional era uma nova feature prometida pro JEE8 ou já existia no JEE7 :-) Sabe como é, sou Springuiniano :p

Valeu!

Guilherme B V Bahia

unread,
Feb 27, 2015, 11:33:25 AM2/27/15
to ce...@googlegroups.com
Sem querer ser chato nem pentelho e sei que não faz muita diferença no nosso dia a dia, mas @Transactional vem desde da expecificação JEE5.

Paulo Jr.

unread,
Feb 27, 2015, 11:39:52 AM2/27/15
to CEJUG
Opa Guilherme, 

Acho que deve estar confundindo não? Procurei na API JEE 5 e não achei: http://docs.oracle.com/javaee/5/api/
A TransactionAttribute sim, como o Ponte falou: http://docs.oracle.com/javaee/5/api/javax/ejb/TransactionAttribute.html

Transactional até onde sei é do JavaEE 7.

Abraço

Rafael Ponte

unread,
Feb 27, 2015, 11:57:42 AM2/27/15
to ce...@googlegroups.com
Isso, Paulo! O @Transactional é que somente veio com JEE7! Antes era o feioso do @TransactionAttribute :-) Mas no final das contas, o dois fazem a mesma coisa!

Se não estou errado, e idéia da nova anotação @Transactional é mais questão de desacoplar o controle transacional do EJB em si, deixando o controle pro CDI e containers non-JEE.

Guilherme B V Bahia

unread,
Feb 27, 2015, 11:59:39 AM2/27/15
to ce...@googlegroups.com, CEJUG
Paulo, 
Estou sim, porque não me expressei bem, estava querendo dizer todo o controle transacional por anotations que você explicou abaixo pode ser feito com anotações @Transaction... 
Não estava querendo me refereir especificamente a uma interface (anotation) do Java, mas ao comportamento transacional da versão JEE5.
Que faz tudo que você explicou anteriormente.

Paulo Jr.

unread,
Feb 27, 2015, 12:05:33 PM2/27/15
to CEJUG
Ah Guilherme, isso aí é verdade, a parte de transação do JavaEE é bem antiga mesmo, não sei com certeza mas acho que até EJB2 já tinha. O motivo de ter diferenciado no primeiro e-mail é o motivo que o Ponte explicou aí acima. Estimular o cara a não ter que fazer EJB's apenas pra ter transação e DI quando o CDI e uma annotation já faz isso pra você.

Acho que falamos todos a mesma coisa :) 

Fabrício, espero que tenha dado pra entender no meio de tanto e-mail hehe

Fabrício Cabral

unread,
Feb 27, 2015, 6:24:42 PM2/27/15
to ce...@googlegroups.com
Olá todos!

@Paulo, muito obrigado pelos esclarecimentos! Ajudou bastante mesmo! Inclusive,
você tocou num ponto que não havia atentado: caso dê alguma coisa errado na
transação o rollback é automático e é preciso ficar atento em como o container
resolve essa questão. Você teria alguma referência (documentação) que possa
aprofundar sobre isso?

@Ponte, agradeço também pela ratificação e pelo link do post no blog da TriadWorks.
Engraçado que sempre acompanho o blog, mas acho que passei batido neste post!

At.te.

2015-02-27 11:54 GMT-03:00 Rafael Ponte <rpo...@gmail.com>:



--
--fx

Paulo Jr.

unread,
Feb 27, 2015, 7:02:32 PM2/27/15
to CEJUG
Opa Fabrício, que bom que ajudou então :)

O JTA faz rollback quando você lança uma RuntimeException, seja sua ou do próprio sistema como NullPointerExc... TransactionException etc...

Por default, apenas Runtime geram rollback. Se quiser que uma exception sua faça rollback, você precisa criar sua exception como runtime. Porém, existem meios de fazer uma Exception fazer rollback e meios de um Runtime não fazer rollback. Aí existem umas annotations que não lembro agora que fazem essa configuração. Mas o básico de saber é que apenas RuntimeException geram rollback, uma Exception comum irá comitar o que já foi enviado ao EntityManager.

O livro do Hébert trata disso nos primeiros capítulos http://www.casadocodigo.com.br/pages/sumario-jpa-eficaz, mas confesso que ainda não li para saber o quanto ele aborta. Mas não tem muito segredo, é basicamente isso aí.

Abraço


Daniel Cunha

unread,
Feb 27, 2015, 8:40:40 PM2/27/15
to CEJUG

Rafael Uchôa

unread,
Feb 28, 2015, 3:13:40 PM2/28/15
to ce...@googlegroups.com
Fabrício,

Só alguns detalhes a mais, o resto, o pessoal já explicou.

Stateful é um EJB que tem estado, ou seja, ele terá um pool de instâncias controlados pelo container. Se sua classe não tem atributos de instância, use Stateless, ou seja, teremos uma instância para todas as threads. Isso é uma questão crucial de performance.

A maioria das aplicações enterprise, elas são feitas em camadas, assim, com certeza você vai querer que todas as classes de negócio, ou as classes que estejam dentro de um certo pacote, vulgo camada, trabalhem em uma transação.

package com.companyx.appy.service;

class UsuarioServiceImpl {
   public void UsuarioService.adicionarUsuario() {
     UsuarioDao.inserir();
     HistoricoUsuarioDao.inserir();
  }
}

Assim, a maneira JEE de controlar as transações é usar @Transactional, a mais simples, mas NÃO a mais segura, pois você precisa garantir que somente as classes de dentro da camada de service estejam com @Transactional. Isso é para aplicações grandes, acredito que aplicações The-ONE-dev, não irá precisar disso.

Se por acaso, por erro ou mal conhecimento, alguém colocar dentro de um DAO um @TransactionAttribute(NEW) em algum método, ele irá criar uma nova transação, e os dados podem em algum momento ficar inconsistentes. Já vi vários casos assim.

A maneira JEE EJB mais segura, seria criar um interceptor, e aplicar em todas as classes de um certo pacote  e não permitir o uso da annotation @Transactional, que pode ser verificado dentro um build da integração contínua ou um simples "grep Transaction *".

ejb-jar.xml:
<assembly-descriptor>
      <!-- Default interceptor that will apply to all methods for all beans in deployment -->
      <interceptor-binding>
         <ejb-name>*</ejb-name>
         <interceptor-class>org.jboss.tutorial.interceptor.bean.DefaultInterceptor</interceptor-class>
      </interceptor-binding>
      ...
   </assembly-descriptor>


A maneira Spring mais segura, seria usar AOP, aplicando um pointcut:

applicationContext.xml:
  <aop:config>
    <aop:pointcut id="productServiceMethods"
            expression="execution(* product.ProductService.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="productServiceMethods"/>
  </aop:config>

  <tx:advice id="txAdvice" transaction-manager="myTxManager">
    <tx:attributes>
      <tx:method name="*" propagation="REQUIRED"/>
      <tx:method name="someOtherBusinessMethod" propagation="REQUIRES_NEW"/>
      <tx:method name="*" propagation="SUPPORTS" read-only="true"/>
    </tx:attributes>
  </tx:advice>



O CDI, por mais que tenha traduzido os interceptors e os decorators para dentro do beans.xml, não trouxeram o pointcut como o ejb-jar.xml, e via código, seria necessário cria uma annotation específica, criando dependência de algum componente corporativo interno. Se isso não for problema, seria a forma mais segura.

@InterceptorBinding
@Target({METHOD, TYPE})
@Retention(RUNTIME)
public @interface Transactional {
}

@Transactional @Interceptor
public class RequiredTransactionInterceptor {
   @AroundInvoke
   public Object manageTransaction(InvocationContext ctx) throws Exception { ... }
}

@Transactional
public class ShoppingCart { ... }


--

Rafael Ponte

unread,
Feb 28, 2015, 3:36:26 PM2/28/15
to ce...@googlegroups.com
Oi Uchoa,

Excelente explicação sobre as alternativas! Contudo, eu discordo sobre a forma mais segura ser via AOP ou interceptors. Levando em consideração que "seguro" significa o desenvolvedor esquecer de algo!

Na verdade considero mais seguro que todo desenvolvedor saiba como funciona o controle transacional do container e, dessa forma, saiba como anotar os métodos ou classes corretamente. 

Prefiro ter o controle transacional explícito no código a tê-lo implícito com AOP. Mas para Services do tipo CRUD eu considero AOP uma boa alternativa, já que existe uma convenção mais explícita no código. 


Um abraço!

Rafael Uchôa

unread,
Feb 28, 2015, 11:57:54 PM2/28/15
to ce...@googlegroups.com
Ponte,

Eu concordo que seria ótimo ter uma equipe nivelada, mas é muito incomum isso ocorrer, devido as restrições de custo dos projetos. O que vejo nos times são alguns devs que tem mais conhecimento de tecnologia, e outros mais de negócio, e isso é bom para a qualidade do software.

E além do que, um minuto olhando o applicationContext com três linhas sobre o poincut (com.companx.appx.Service.*) ou a classe com o @Configuration, não resolva.

A maioria das aplicações corporativas com um mínimo de organização, teem algumas camadas, ou seja, ui -> business -> integration (DAO, Mail, barramentos, etc), assim, você acaba colocando a abertura e o fechamento da transação em uma delas.

Quanto ao "esquecer", as vezes, é interessante esquecer um pouco dos detalhes de tecnologia e focar na lógica de negócio, na verdade, a gente precisa fazer isso quando as regras são muito complicadas. Tem até algumas vertentes ainda que falam que o código tem ser mais o próximo possível do negócio, e sendo assim, vê um @Transactional é pura tecnologia, além de criar mais dependência nas classes de negócio.

Quanto ao XML, é pura preguiça mesmo, de migrar para o @Configuration e usar o @EnableTransactionManagement. Uma boa para uma evolução do seu post. Configurar o AOP para o gerenciamento de transação usando @Configuration, assim a gente ganhava um pouco de Compiler-Check, pena que não dá para referenciar um package em java via código. (ou dá ?, Java 8, onde está você meu filho ??!! rs...)


Reply all
Reply to author
Forward
0 new messages