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 { ... }