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
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 EMF 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.
I am putting down what I have finally gathered. From the section "Implementing DAOs based on plain JPA" in the Spring Reference:
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.
This means as per JPA specifications EntityManager instances are not thread safe, but if Spring handles them, they are made thread safe.
If you are using Spring, it is better to inject EntityManagers instead of EntityManagerFactory.
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.
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.