getting javax.persistence.TransactionRequiredException in a container managed Entity Manager

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

  •  20-12-2019
  •  | 
  •  

Question

Hi I created a simple JSF + JPA application. my web app consists of an Entity, a ManagedBean and some JSF pages. It's purpose is to create and store an object in the MySQL database. I get javax.persistence.TransactionRequiredException every time I want to persist the entity into the PersistenceContxt. However when injecting the UserTransaction into the controller class it works without any problem, but I cannot understand why? Because it is supposed to need not to add UserTransaction because it is container managed. Am i wrong or what? or there are other issues in my codes?

Here is my 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";
    }
}

Here is the create.xhtml facelet:

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

and this is the Persistence.xml content:

<?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>
Was it helpful?

Solution

Transaction is automatically created only for methods in EJB, not for manged beans. If you are in JEE7 container you may try to add @Transactional to your Controller managed bean, otherwise you need to use UserTransation to manage the transaction.

Here is piece of code that I've used:

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

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

And I'm calling it from the servlet:

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

I can see in database that it was saved, and in the logs I see following messages:

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

So as you can see new transaction is crated and object is saved

OTHER TIPS

Having looked at the code snippet. I think this is rather a design issue than a technical issue. I suggest that you should consider structuring your application as follow: 1. Database layer - MySql. 2. Entities package - contains entity objects that map directly to your database tables. 3. Data Access Objects Package - contains EJBs (e.g. @Singleton, @Stateless, @Stateful). 4. Controller Package - contains the servlet and/or managed beans which are accessed by the presentation layer through EL(e.g. @Named, @ConversionScoped, @ManagedBean, etc) 5. Presentation layer - JSF pages (e.g. index.xhtml, etc)

It is important to structure your code this way because transactions and security and other services are automatically provided for EJBs which is where persistence should be performed. That is, reference to the EntityManager (through @PersistenceContext)should be made in EJBs not in the Managed Beans objects. The objects in the controller should use @Inject (@EJB) annotations to inject dependencies.

Unless your operation is to read from database, only one thing that you need is "@Transactional" annotation above your method. Also you can define it above your class. But it's not proper architecture. At least you have to create another class and inject it on your bean.

If you are using JavaEE, you should use EJB. It's easy and you don't need to worry about transaction. Container can control whole thing.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top