Ottenere Javax.persistence.TransactionRequeredException in un manager di Entity gestito container

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

  •  20-12-2019
  •  | 
  •  

Domanda

Ciao ho creato un'applicazione JSF + JPA.La mia app Web è composta da un Entity, un ManagedBean e alcune pagine JSF.Lo scopo è quello di creare e memorizzare un oggetto nel database MySQL.Ottengo javax.persistence.TransactionRequiredException ogni volta che voglio persistere l'entità nel PersistenceContxt.Tuttavia, quando iniettando il UserTransaction nella classe del controller funziona senza alcun problema, ma non riesco a capire perché?Perché dovrebbe non essere necessario aggiungere UserTransaction perché è gestito dal contenitore.Sono sbagliato o cosa?Oppure ci sono altri problemi nei miei codici?

Ecco il mio codice gestito:

@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";
    }
}
.

Ecco la fascetta create.xhtml:

...
<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" />
...
.

E questo è il contenuto Persistence.xml:

<?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>
.

È stato utile?

Soluzione

La transazione viene creata automaticamente solo per i metodi in EJB, non per i fagioli gestiti. Se sei in contenitore Jee7 potresti provare ad aggiungere @Transactional al tuo controller bean gestito, altrimenti è necessario utilizzare UserTransAtion per gestire la transazione.

Qui è un pezzo di codice che ho usato:

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

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

e lo sto chiamando dal servlet:

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

Posso vedere nel database che è stato salvato, e nei registri vedo i seguenti messaggi:

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

Così come puoi vedere la nuova transazione è ricreata e l'oggetto viene salvato

Altri suggerimenti

Avendo guardato lo snippet di codice. Penso che questo sia piuttosto un problema di progettazione che un problema tecnico. Suggerisco che dovresti prendere in considerazione la possibilità di strutturare la tua applicazione come segue: 1. Layer di database - MySQL. 2. Pacchetto di entità - contiene oggetti di entità che mappano direttamente alle tabelle del database. 3. Pacchetto di oggetti di accesso ai dati - contiene EJBS (ad es. @Singleton, @stateless, @stetyful). 4. Pacchetto controller - contiene il servlet e / o i fagioli gestiti a cui si accede dal livello di presentazione tramite EL (E.G. @Nymed, @ConversionsCoped, @Managedbean, ecc.) 5. Layer di presentazione - pagine JSF (ad es. Index.xhtml, ecc.)

È importante strutturare il tuo codice in questo modo perché le transazioni e la sicurezza e altri servizi vengono automaticamente forniti per EJB che è dove deve essere eseguita la persistenza. Cioè, il riferimento all'entitàManager (attraverso @persistenceContext) dovrebbe essere effettuato in EJBS non negli oggetti dei fagioli gestiti. Gli oggetti nel controller dovrebbero utilizzare le annotazioni @Inject (@ejb) su iniettare le dipendenze .

A meno che il tuo funzionamento non venga letto dal database, solo una cosa di cui hai bisogno è l'annotazione "@Transactional" sopra il tuo metodo.Inoltre puoi definirlo sopra la tua classe. Ma non è un'architettura adeguata.Almeno devi creare un'altra classe e iniettarlo sul tuo fagiolo.

Se stai usando Javaee, dovresti usare EJB.È facile e non è necessario preoccuparsi della transazione.Il contenitore può controllare l'intera cosa.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top