Using ThreadLocal and Servlet Filters to cleanly access JPA an EntityManager

My current project is slowly moving from JDBC-based database interaction to JPA-based. Following good sense, I’m trying to change things as little as possible. One of those things is that we are deploying under Tomcat and not under a full-blown J2EE container. This means that EJB3 is out. After my post regarding this configuration, I quickly realized that my code started to get littered with:

EntityManager em = null;
try
{
  em = EntityManagerUtil.getEntityManager();
  // do stuff with entity manager
}
finally
{
  try {
    if (em != null) em.close();
  } catch (Throwable t) {
    logger.error("While closing an EntityManager",t);
  }
}

Pretty ugly, and seriously annoying to have to add 13 lines of code to any method that needs to interact with the database. The Hibernate docs suggest using ThreadLocal variables to provide access to the EntityManager throughout the life of a request (which wouldn’t really work for a Swing app, but since this is servlet-based, it should work fine). The ThreadLocal javadocs contain possibly the most annoying example ever, and I didn’t follow how to use it.

Anyway, I finally got around to it, and also solved the close problem as well, by using a Servlet Filter. I guess this type of thing would normally be solvable by Spring or Guice, but I didn’t want to drag all of that into the application to refactor this one thing; I would’ve easily spent the rest of the day dealing with XML confihuration and deployment.

The solution was quite simple:

/** Provides access to the entity manager.  */
public class EntityManagerUtil
{
    public static final ThreadLocal<EntityManager>
        ENTITY_MANAGERS = new ThreadLocal<EntityManager>();

    /** Returns a fresh EntityManager */
    public static EntityManager getEntityManager()
    {
        return ENTITY_MANAGERS.get();
    }
}
public class EntityManagerFilter implements Filter
{
    private Logger itsLogger = Logger.getLogger(getClass().getName());
    private static EntityManagerFactory theEntityManagerFactory = null;

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException
    {
        EntityManager em = null;
        try
        {
            em = theEntityManagerFactory.createEntityManager();
            EntityManagerUtil.ENTITY_MANAGERS.set(em);
            chain.doFilter(request,response);
            EntityManagerUtil.ENTITY_MANAGERS.remove();
        }
        finally
        {
            try
            {
                if (em != null)
                    em.close();
            }
            catch (Throwable t) {
                itsLogger.error("While closing an EntityManager",t);
            }
        }
    }
    public void init(FilterConfig config)
    {
        destroy();
        theEntityManagerFactory =
          Persistence.createEntityManagerFactory("gliffy");
    }
    public void destroy()
    {
        if (theEntityManagerFactory != null)
            theEntityManagerFactory.close();
    }
}

So, when the web app gets deployed, the entity manager factory is created (and closed when the web app is removed). Each thread that calls EntityManagerUtil to get an EntityManager gets a fresh one that persists for the duration of the request. When the request is completed, the entity manager is closed automatically.

Tags: , , ,

5 Responses to “Using ThreadLocal and Servlet Filters to cleanly access JPA an EntityManager”

  1. mbinette says:

    Is there a reason you didn’t use a ServletContextListener instead of a filter?

    I am using a solution that works similarly but only creates the EntityManager once instead of for each request. Is there a reason why you would want to close the EntityManager after every request?

  2. Dave says:

    My understanding of how EntityManager works is that you need one per transaction; if all requests were using the same instance, a rollback from one thread would rollback all threads.

    I’m not sure how this works in EJB3.0, but it seems to insert one for each EJB transaction. The docs for Hibernate recommended this approach, but it may not be the only one.

    Also, ServletContextListener doesn’t allow you to examine the results of the servlet call; in my case, any exception thrown by the servlet call results in a rollback, this way my code doesn’t have to worry about committing or rolling back; it can just proceed as normal. If we ever went to full-blown EJB3, not much of the code would need to change.

  3. mbinette says:

    When I said I create the EntityManager once instead of for each request, I meant to add that it is per thread using ThreadLocal like you have done. So all requests on the same thread will use the same EntityManager but requests on another thread will use a different EntityManager.

    I didn’t use a Filter because a lot of my requests don’t need an EntityManager. I hadn’t thought of the automatic rollback. Right now we catch the exception in our “service” code and don’t have a generic catch all to perform that action. That is a big benefit to using a Filter like you have done.

  4. jaxent says:

    Thanks for posting that. It was one of those, “Why didn’t I think of that?” moments. Saves me a lot time and resource leak potential.

  5. [...] Thread-Local Variables In Java Threading lightly, Part 3: Sometimes it’s best not to share Using ThreadLocal and Servlet Filters to cleanly access JPA an EntityManager Thread-local variables in Java Introduction to reducing thread contention in Java Possibly related [...]