obtener javax.persistence.TransactionRequiredException en un Entity Manager administrado por contenedor

StackOverflow https://stackoverflow.com//questions/24001269

  •  20-12-2019
  •  | 
  •  

Pregunta

Hola, creé un simple JSF + JPA solicitud.mi aplicación web consta de un Entity, a ManagedBean y algo JSF páginas.Su propósito es crear y almacenar un objeto en la base de datos MySQL.yo obtengo javax.persistence.TransactionRequiredException cada vez que quiero persistir la entidad en el PersistenceContxt.Sin embargo, al inyectar el UserTransaction en la clase de controlador funciona sin ningún problema, pero no puedo entender por qué.Porque se supone que no es necesario agregar UserTransaction porque está administrado por contenedores.¿Me equivoco o qué?¿O hay otros problemas en mis códigos?

Aquí está mi código ManagedBean:

@ManagedBean
@SessionScoped
public class Controller {
    @PersistenceContext
    private EntityManager em;
    private Book book;
    public Controller() {}

    public Book getBook() {
        return book;
    } 

    public void setBook(Book book) {
        this.book = book;
    }

    public String createBook() {
        book = new Book();
        return "create";
    }

    public String showResponse() {
        em.persist(book);
        return "response";
    }
}

Aquí está el create.xhtml faceta:

...
<h:form>
    <h:panelGrid columns="2">
        <h:outputText>Title</h:outputText>
        <h:inputText value="#{controller.book.title}" />
    </h:panelGrid>
</h:commandButton action="#{controller.showResponse()}" value="Response" />
...

y este es el Persistence.xml contenido:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
  <persistence-unit name="JPATestPU" transaction-type="JTA">
    <jta-data-source>jdbc/mysql</jta-data-source>
    <properties>
      <property name="javax.persistence.schema-generation.database.action" value="create"/>
    </properties>
  </persistence-unit>
</persistence>
¿Fue útil?

Solución

La transacción se crea automáticamente solo para métodos en EJB, no para beans administrados.Si está en el contenedor JEE7, puede intentar agregar @Transactional a su bean administrado por el Controlador; de lo contrario, deberá usar UserTransation para administrar la transacción.

Aquí hay un fragmento de código que he usado:

@Transactional
public class PersonService {
    @PersistenceContext 
    private EntityManager em;

    public void savePerson(Person person) {
    em.persist(person);
}

Y lo llamo desde el servlet:

 @WebServlet("/MyServlet")
 public class MyServlet extends HttpServlet {
    @Inject
    PersonService service;
  ....
  service.savePerson(p);
  System.out.println("Person saved");

Puedo ver en la base de datos que se guardó y en los registros veo los siguientes mensajes:

INFO: Managed bean with Transactional annotation and TxType of REQUIRED called outside a transaction context.  Beginning a transaction...
INFO: Person saved

Como puede ver, se crea una nueva transacción y se guarda el objeto.

Otros consejos

Habiendo mirado el fragmento de código.Creo que esto es más una cuestión de diseño que técnica.Le sugiero que considere estructurar su aplicación de la siguiente manera:1.Capa de base de datos - MySql.2.Paquete de entidades: contiene objetos de entidad que se asignan directamente a las tablas de su base de datos.3.Paquete de objetos de acceso a datos: contiene EJB (p. ej.@Singleton, @Stateless, @Stateful).4.Paquete de controlador: contiene el servlet y/o los beans administrados a los que accede la capa de presentación a través de EL (p. ej.@Named, @conversionscoped, @ManagedBean, etc) 5.Capa de presentación: páginas JSF (p. ej.index.xhtml, etc.)

Es importante estructurar su código de esta manera porque las transacciones, la seguridad y otros servicios se proporcionan automáticamente para los EJB, que es donde se debe realizar la persistencia.Es decir, la referencia al EntityManager (a través de @PersistenceContext) debe hacerse en EJB, no en los objetos Managed Beans.Los objetos en el controlador deben usar anotaciones @Inject (@EJB) para inyectar dependencias.

A menos que su operación sea leer desde la base de datos, lo único que necesita es la anotación "@Transactional" encima de su método.También puedes definirlo encima de tu clase.Pero no es una arquitectura adecuada.Al menos tienes que crear otra clase e inyectarla en tu bean.

Si está utilizando JavaEE, debe utilizar EJB.Es fácil y no necesita preocuparse por la transacción.El contenedor puede controlar todo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top