views:

4816

answers:

4

A long question, please bear with me.

We are using Spring+JPA for a web application. My team is debating over injecting EntityManagerFactory in the GenericDAO(a DAO based on Generics something on the lines provided by APPFUSE, we do not use JpaDaosupport for some reason) over injecting an EntityManager. We are using "application managed persistence".

The arguments against injecting a EntityManagerFactory is that its too heavy and so is not required, the EntityManager does what we need. Also, as Spring would create a new instance of a DAO for every web request(I doubt this) there are not going to be any concurrency issues as in the same EntityManager instance is shared by two threads.

The argument for injecting EFM is that its a good practice over all its always good to have a handle to a factory.

I am not sure which is the best approach, can someone please enlighten me?

SB

A: 

I found that setting the @Repository Spring annotation on our DAOs and having EntityManager managed by Spring and injected by @PersistenceContext annotation is the most convenient way to get everything working fluently. You benefit from the thread safety of the shared EntityManager and exception translation. By default, the shared EntityManager will manage transactions if you combine several DAOs from a manager for instance. In the end you'll find that your DAOs will become anemic.

Gaël Marziou
+8  A: 

The pros and cons of injecting EntityManagerFactory vs EntityManager are all spelled out in the Spring docs here, I'm not sure if I can improve on that.

Saying that, there are some points in your question that should be cleared up.

...Spring would create a new instance of a DAO for every web request...

This is not correct. If your DAO is a Spring bean, then it's a singleton, unless you configure it otherwise via the scope attribute in the bean definition. Instantiating a DAO for every request would be crazy.

The argument for injecting EFM is that its a good practice over all its always good to have a handle to a factory.

This argument doesn't really hold water. General good practice says that an object should be injected with the minimum collaborators it needs to do its job.

skaffman
+1  A: 

I am putting down what I have finally gathered...

Although EntityManagerFactory instances are thread-safe, EntityManager instances are not. The injected JPA EntityManager behaves like an EntityManager fetched from an application server's JNDI environment, as defined by the JPA specification. It delegates all calls to the current transactional EntityManager, if any; otherwise, it falls back to a newly created EntityManager per operation, in effect making its usage thread-safe. -- From Spring Reference

This means as per JPA specifications EntityManager instances are not thread safe, but if Spring handles them, they are made Threadsafe.


If you are using Spring, it is better to inject EntityManagers instead of EntityManagerFactory.


SB
+1  A: 

I think this has already been well covered, but just to reinforce a few points.

  • The DAO, if injected by Spring, is a singleton by default. You have to explicitly set the scope to prototype to create a new instance every time.

  • The entity manger injected by @PersistenceContext is thread safe.

That being said, I did have some issues on with a singleton DAO in my multi-threaded application. I ended up making the DAO a instanced bean and that solved the problem. So while the documentation may say one thing, you probably want to test your application thoroughly.

Follow-up:

I think part of my problem is I am using

@PersistenceContext(unitName = "unit",
    type = PersistenceContextType.EXTENDED)

If you use PersistenceContextType.EXTENDED, keep in mind you have to, if I understand correctly, manually close the transaction. See this thread for more information.

Another Follow-up:

Using an instanced DAO is an extremely bad idea. Each instance of the DAO will have its own persistence cache and changes to one cache will not be recognized by other DAO beans. Sorry for the bad advice.

James McMahon