The Source for Java Technology Collaboration
User: Password:



 Sahoo

Sahoo's Blog

EntityManager.persist() throws TransactionRequiredException in a servlet?

Posted by ss141213 on December 05, 2005 at 09:37 AM | Comments (3)

In my last blog I discussed about using Java Persistence API in a web application. In this article I shall talk about a very common mistake that a web-app developer commits and how to fix it. Java Persistence API is part of Java EE 5 platform which is being reference implemented in open source project called glassfish.

Code that does not work:
Given below is the code snippet of a servlet which uses an entity bean called UserCredential using a container managed EntityManager.

public class RegistrationServlet extends HttpServlet {
// This injects the default persistence unit.
@PersistenceUnit private EntityManagerFactory emf;
public void service (HttpServletRequest req , HttpServletResponse resp)
throws ServletException, IOException {
try {
resp.setContentType("text/html");
PrintWriter out = resp.getWriter();
...
String name = req.getParameter("name");
String password = req.getParameter("password");
UserCredential credential = new UserCredential(name, password);
EntityManager em = emf.getEntityManager(); // container managed em
// em.persist makes the new object as persistent and managed.
em.persist(credential);
out.println("Successfully created the new user. ");
} catch (Exception nse) {
throw new ServletException(nse);
}
}
// other servlet methods like init etc. are omitted for bravity.
}

Exception Details:
When the service() method gets executed, this servlet gets the following exception:
javax.persistence.TransactionRequiredException:
Exception Description: Error marking externally managed transaction for rollback

Why this exception occurs?
If you refer to persist() method in EntityManager.java you can see the javadocs clearly mention that persist throws javax.persistence.TransactionRequiredException if there is no transaction. Since we did not start a transaction in the service() method in servlet before calling em.persist(), the servlet got the exception.

What is the fix?
To fix this, update the servlet code as given below (new code is in bold face letter):

public class RegistrationServlet extends HttpServlet {
// This injects the default persistence unit.
@PersistenceContext private EntityManagerFactory emf;
// This injects a user transaction object.
@Resource private UserTransaction utx;
public void service (HttpServletRequest req , HttpServletResponse resp)
throws ServletException, IOException {
try {
resp.setContentType("text/html");
PrintWriter out = resp.getWriter();
...
String name = req.getParameter("name");
String password = req.getParameter("password");
// we must begin a tx.
utx.begin();
UserCredential credential = new UserCredential(name, password);
EntityManager em = emf.getEntityManager(); // container managed em
// em.persist makes the new object as persistent and managed.
em.persist(credential);
// commit the transaction,
// b'cos web container rollbacks unfinished tx at the end of request
utx.commit();
out.println("Successfully created the new user. ");
} catch (Exception nse) {
throw new ServletException(nse);
}
}
// other servlet methods like init etc. are omitted for bravity.
}

Comparison with equivalent code in a Session Bean
Let's compare the difference in behavior between a servlet and an ejb.
Given below is a stateless session bean that has a business interface called PasswordManager which has a method of type "void createNewUser(String, String)".

@Stateless
class PasswordManagerBean implements PasswordManager {
@PersistenceContext private EntityManager em;
public void createNewUser(String name, String password) {
UserCredential credential = new UserCredential(name, password);
// em.persist makes the new object as persistent and managed.
em.persist(credential);
}
}

Let's analyse the differences between ejb and servlet code:
Of course ejb code does not have the HttpResponse related code. The other significant difference is that ejb uses @PersistenceContext to get hold of an EntityManager where as the servlet uses @PersistenceUnit to get hold of an EntityManagerFactory and then calls getEntityManager() on the injected EntityManagerFactory to get hold of an EntityManager. The reason why the servlet does not use @persistenceContext is discussed here. That's not the point I am trying to make here. See that the entity creation code and EntityManager interaction code is exacty same as it was in the original servlet code. Yet the servlet gets the exception where as the ejb works. You are wondering why?
For the EJB, default transaction management type is CONTAINER and default transaction attribute for a business method is REQUIRED. So even though we did not specify transaction attributes in our bean class, defaults took over. So even if the business method does not start a transaction, the EJB container starts a transaction if the business method is called in null transaction context and ends it at the end of business method. Hence em.persist() works. For servlet, web container does not implicitly starts a transaction. The web container is only required to roll back a transaction if service() method leaves behind an unfinished transaction.
Hope this helped!
Technorati Tags:
More blogs about glassfish.


Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • Original posting used @PersistenceContext in the servlet. I have now changed it to use @PersistenceUnit together with getEntityManager().

    -- Sahoo

    Posted by: ss141213 on January 03, 2006 at 07:24 PM

  • Hello,
    So EVEN in 'Container Managed Entity Manager' in web container, the container will NOT start transaction, which has to be manually started.
    Is there another way in web container, so that we do not have to manually manage transaction via utx.begin() and utx.commit ?

    Thank You.

    Posted by: javanet_user on December 07, 2007 at 04:42 PM

  • No, there is no alternative to user managing the transactions explicitly in a web application.

    Sahoo

    Posted by: ss141213 on December 09, 2007 at 08:07 PM





Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds