Abrufen von javax.persistence.TransactionRequiredException in einem vom Container verwalteten Entity Manager

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

  •  20-12-2019
  •  | 
  •  

Frage

Hallo, ich habe ein einfaches erstellt JSF + JPA Anwendung.Meine Web-App besteht aus einem Entity, A ManagedBean und einige JSF Seiten.Sein Zweck besteht darin, ein Objekt in der MySQL-Datenbank zu erstellen und zu speichern.Ich bekomme javax.persistence.TransactionRequiredException jedes Mal, wenn ich die Entität in der beibehalten möchte PersistenceContxt.Allerdings beim Injizieren der UserTransaction in die Controller-Klasse funktioniert es problemlos, aber ich verstehe nicht warum?Weil es angeblich nicht hinzugefügt werden muss UserTransaction weil es Container-verwaltet ist.Liege ich falsch oder was?Oder gibt es andere Probleme in meinen Codes?

Hier ist mein ManagedBean-Code:

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

Hier ist das create.xhtml Facette:

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

und das ist das Persistence.xml Inhalt:

<?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>
War es hilfreich?

Lösung

Transaktionen werden automatisch nur für Methoden in EJB erstellt, nicht für verwaltete Beans.Wenn Sie sich im JEE7-Container befinden, können Sie versuchen, @Transactional zu Ihrer vom Controller verwalteten Bean hinzuzufügen. Andernfalls müssen Sie UserTransation zum Verwalten der Transaktion verwenden.

Hier ist ein Teil des Codes, den ich verwendet habe:

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

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

Und ich rufe es vom Servlet aus auf:

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

Ich kann in der Datenbank sehen, dass es gespeichert wurde, und in den Protokollen sehe ich folgende Meldungen:

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

Wie Sie sehen, wird eine neue Transaktion erstellt und das Objekt gespeichert

Andere Tipps

Nachdem ich mir den Codeausschnitt angesehen habe.Ich denke, das ist eher ein Designproblem als ein technisches Problem.Ich schlage vor, dass Sie Ihre Bewerbung wie folgt strukturieren sollten:1.Datenbankschicht – MySql.2.Entities-Paket – enthält Entity-Objekte, die direkt Ihren Datenbanktabellen zugeordnet sind.3.Data Access Objects Package – enthält EJBs (z. B.@Singleton, @Stateless, @Stateful).4.Controller-Paket – enthält das Servlet und/oder die verwalteten Beans, auf die die Präsentationsschicht über EL zugreift (z. B.@Named, @ConversionScoped, @Managedbean usw.) 5.Präsentationsschicht – JSF-Seiten (z. B.index.xhtml usw.)

Es ist wichtig, Ihren Code auf diese Weise zu strukturieren, da Transaktionen, Sicherheit und andere Dienste automatisch für EJBs bereitgestellt werden, in denen die Persistenz durchgeführt werden sollte.Das heißt, der Verweis auf den EntityManager (über @PersistenceContext) sollte in EJBs erfolgen, nicht in den Managed Beans-Objekten.Die Objekte im Controller sollten @Inject (@EJB)-Annotationen verwenden injizieren Abhängigkeiten.

Sofern Ihr Vorgang nicht darin besteht, aus einer Datenbank zu lesen, benötigen Sie lediglich die Annotation „@Transactional“ über Ihrer Methode.Sie können es auch über Ihrer Klasse definieren.Aber es ist keine richtige Architektur.Zumindest müssen Sie eine weitere Klasse erstellen und diese in Ihre Bean einfügen.

Wenn Sie JavaEE verwenden, sollten Sie EJB verwenden.Es ist ganz einfach und Sie müssen sich nicht um die Transaktion kümmern.Der Container kann das Ganze steuern.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top