Handle multiple EntityManager in Java EE application

Olivier J. picture Olivier J. · Dec 4, 2012 · Viewed 15.1k times · Source

I have Java EE application with about 10 EntityManagers (number of EMs will probably increase). My application also contains many stateless, statefull and message driven beans.

Rather than inject in each bean my EMs with @PersistenceContext (and 2 methods to detect which EM to use for user), I probably store all of that inside a singleton bean and access it with others beans. Like that, no worries about maintainability.

Nevertheless, is it thread-safe to store EMs inside one singleton bean? Can a bottleneck appear?

Another solution is to create an abstract class and all beans will extend it.

What is the better solution?

Answer

Arjan Tijms picture Arjan Tijms · Dec 7, 2012

An entity manager is not supposed to be thread-safe, so you shouldn't share ones via a Singleton. It's the same reason as why you should not inject an entity manager into a Servlet, and why a lookup from JNDI in such a web component -should- return a different instance of the entity manager ever time.

In practice some implementations may provide an entity manager that is thread-safe, so during testing it may seem to work. However, for the sake of portability and to protect you against upgrade woes, you should never rely on this.

Instead of inheriting from a common base class, you could define all your entity managers in one bean, and inject that wherever you need an entity manager.

E.g.

@Stateless
public class EntityManagerProviderBean {

    @PersistenceContext(unitName="foo")
    private EntityManager entityManagerFoo;

    @PersistenceContext(unitName="bar")
    private EntityManager entityManagerBar;

    public EntityManager getEntityManager() {
        return ...? entityManagerFoo : entityManagerBar;
    }
}

(where ... is the logic you use to select the right entity manager)

Inject this into a bean needing an entity manager:

@Stateless
public class MyService {

    @EJB
    private EntityManagerProviderBean entityManagerProvider;

    public void doStuff(MyEntity myEntity) {
        entityManagerProvider.getEntityManager().update(myEntity);
    }

}

Alternatively the following would perhaps be even neater:

@Stateless
@PersistenceContexts({ 
    @PersistenceContext(unitName="foo", name = "fooENC"),
    @PersistenceContext(unitName="bar", name = "barENC") }
)
public class EntityManagerProviderBean {

    @Resource
    private EJBContext context;

    public EntityManager getEntityManager() {
        return (EntityManager) context.lookup(... ? "fooENC" : "barENC");
    }
}

The last example maps all persistence contexts into the ENC of the bean, where they can be conveniently retrieved programmatically.

Unfortunately, people forgot to add tests for the latter syntax to the TCK and subsequently major vendors forgot to implement it (see http://java.net/jira/browse/JPA_SPEC-38 and https://issues.jboss.org/browse/AS7-5549), so test if this works on your server.