TransactionRequiredException ao persistir o EntityManager

Boa noite pessoal

Estou tentando utilizar JPA e JTA mas quando chega na linha da persistência da erro de TransactionRequiredException. Abaixo os arquivos:

persistence.xml


<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
    <persistence-unit name="TesteJPA_JTAPU" transaction-type="JTA">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <jta-data-source>jdbc/TesteJPAJTA</jta-data-source>
        <exclude-unlisted-classes>false</exclude-unlisted-classes>
        <properties>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.format_sql" value="true"/>
        </properties>
    </persistence-unit>
</persistence>

Pessoa.java


package br.com.tebosoftware.modelo;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

/**
 *
 * @author Shubacca
 * @date 24/08/2012
 */
@Entity
public class Pessoa implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String nome;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 41 * hash + (this.id != null ? this.id.hashCode() : 0);
        hash = 41 * hash + (this.nome != null ? this.nome.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Pessoa other = (Pessoa) obj;
        if (this.id != other.id && (this.id == null || !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }
}

PessoaController.java


package br.com.tebosoftware.controller;

import br.com.tebosoftware.modelo.Pessoa;
import java.io.Serializable;
import java.util.List;
import javax.ejb.Stateful;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

/**
 *
 * @author Shubacca
 * @data 24/08/2012
 */
@ManagedBean
@ViewScoped
@Stateful
@TransactionAttribute(TransactionAttributeType.SUPPORTS)
public class PessoaController implements Serializable {

    @PersistenceContext//(unitName = "TesteJPA_JTAPU")
    private EntityManager entityManager;
    private Pessoa pessoa;
    private List<Pessoa> pessoas;

    public Pessoa getPessoa() {
        if (pessoa == null) {
            pessoa = new Pessoa();
        }
        return pessoa;
    }

    public void setPessoa(Pessoa pessoa) {
        this.pessoa = pessoa;
    }

    public void novo() {
        pessoa = null;
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void gravar() {
        entityManager.persist(pessoa);
        pessoa = null;
        pessoas = null;
    }

    public List<Pessoa> getPessoas() {
        if (pessoas == null) {
            pessoas = entityManager.createQuery("from Pessoa order by nome").getResultList();
        }
        return pessoas;
    }
}

Erro:

javax.faces.el.EvaluationException: javax.persistence.TransactionRequiredException
	at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:102)
	at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102)
	at javax.faces.component.UICommand.broadcast(UICommand.java:315)
	at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:794)
	at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1259)
	at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81)
	at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
	at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
	at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
	at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1550)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
	at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
	at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:161)
	at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:331)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
	at com.sun.enterprise.v3.services.impl.ContainerMapper$AdapterCallable.call(ContainerMapper.java:317)
	at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195)
	at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:860)
	at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:757)
	at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1056)
	at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:229)
	at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
	at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
	at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
	at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
	at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
	at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
	at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
	at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
	at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
	at java.lang.Thread.run(Thread.java:722)
Caused by: javax.persistence.TransactionRequiredException
	at com.sun.enterprise.container.common.impl.EntityManagerWrapper.doTxRequiredCheck(EntityManagerWrapper.java:163)
	at com.sun.enterprise.container.common.impl.EntityManagerWrapper.doTransactionScopedTxCheck(EntityManagerWrapper.java:145)
	at com.sun.enterprise.container.common.impl.EntityManagerWrapper.persist(EntityManagerWrapper.java:263)
	at br.com.tebosoftware.controller.PessoaController.gravar(PessoaController.java:47)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:601)
	at javax.el.BeanELResolver.invokeMethod(BeanELResolver.java:779)
	at javax.el.BeanELResolver.invoke(BeanELResolver.java:528)
	at javax.el.CompositeELResolver.invoke(CompositeELResolver.java:257)
	at com.sun.el.parser.AstValue.invoke(AstValue.java:248)
	at com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:302)
	at org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:39)
	at org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50)
	at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105)
	at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:88)
	... 32 more

Desde já agradeço

Já pensou em separar funções? Serio mesmo que você vai querer uma classe que seja MB, EJB ao mesmo tempo? Código acoplado?

Você sabe o impacto do @TransactionAttribute(TransactionAttributeType.SUPPORTS) ? Se estudar mais nisso aqui você acha o problema.

Cara isso era só um teste que eu estava fazendo pois hoje eu controlo através de AOP. Sua resposta foi muito superficial.

jakefrog, gostaria de pedir desculpa e agradecer pois o que você disse faz todo o sentido. Fiz um teste separando as lógicas (que normalmente faço mas não o fiz no teste e funcionou normal).

Você teria um material para me enviar?

grato

Se eu lançar um exception não deveria dar rollback?

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void gravar() throws Exception {
        entityManager.persist(pessoa);
        pessoa = null;
        pessoas = null;
        for (int i = 1; i < 10; i++) {
            Pessoa _pessoa = new Pessoa();
            _pessoa.setNome(_pessoa.getNome() + i);
            entityManager.persist(_pessoa);
            throw new Exception("Teste");
        }
    }

Não.

O EJB trabalha com o conceito de Application exception e System Exception. Mais detalhes sobre isso você encontra nesse livro: http://www.amazon.com/Enterprise-JavaBeans-3-0-5th-Edition/dp/059600978X/ref=sr_1_8?ie=UTF8&qid=1346332694&sr=8-8&keywords=ejb+3

Eu indico a todos, mas não indico a versão 3.1

Já trabalhei com Delphi e sei como ele é mais “simples”, existem os modos simples em Java mas você terá que abrir mão da praticidade do EJB controlar a transação para você.

Resumidamente se você simplesmente lançar uma exceção verificada, não haverá rollback da transação.

Se você quer dar rollback na transação ao lançar uma exceção verificada, tem que anotar com @ApplicationException(rollback = true).

Se você lançar uma exceção não-verificada, aí sim haverá o rollback da transação, e o container irá destruir a instância do EJB.

Ok vou comprar o livro. Obrigado