JPA EntityManager Static or Instance?

大憨熊 提交于 2019-12-22 04:54:07

问题


I've built some JPA stuff in the past that used an instance of the javax.persistence.EntityManager per instance of DAO; this is the way most examples are setup.

public class BaseDaoThatEveryDaoExtends {
   @PersistenceContext
   private EntityManager entityManager;
}

I've just stumbled upon code that uses a static javax.peristence.EntityManger injected by a PersistenceContext annotation, the architect tells me this causes no problems and they never had any problem even in a clustered application with JTA and an XA data source:

public class BaseDaoThatEveryDaoExtends {
   @PersistenceContext
   private static EntityManager entityManager;
}

As far as I can tell this is an anti-pattern as the EntityManager holds some state information and making it static makes that whole state application wide. Also this makes the classes very hard to test.

Are there other drawbacks to doing this or is this a standard way of using an EntityManager ?


回答1:


I think the major risk is not in the EntityManager itself, but in the application context that is attached to the entity manager when it is used.

Let's assume you have two different clients making a request to your server, both invoking two different methods of your application, both running on different threads, but both using the same entity manager.

As far as I know the entity manager will have a single context attached to it, this context will be shared by both clients. Every time you load an instance to the context, will be available to threads through the shared entity manager. What will happen if they tamper with each other's data? What will happen if they are using different transaction isolation configuration?. How can you possibly be sure that client 1 is not altering data being currently used by client 2?

What if one of the clients invalidates the context, what will the other do? How do you deal with concurrency this way?




回答2:


EntityManager holds onto its data using a threadlocal, so it may be ok to hold a static reference to it since all the threads accessing it would be handled independently. In fact, I would not be surprised if the EJB context holds onto the EntityManager in a static way, using a singleton pattern.

Personally, I would never define it in a static way. It seems unnecessary, and at worst may have some unforeseen side effects.

One problem I can see is the ability to inadvertently accessing the entityManager from a static method:

public class BaseDaoThatEveryDaoExtends {
   @PersistenceContext
   private static EntityManager entityManager;

   public static void doSomeStaticWork(){
      ...
      entityManager.doSomething; //NPE possible!
   }
}

I could see the EntityManager not being injected and resulting in a NPE in this case.

Other than that there may be some issues around testing/mocking using the EntityManager.




回答3:


The EntityManagerFactory is guaranteed to be thread-safe, so I think this is the "correct" way: Use the EMF in the thread-un-safe places and protect the EntityManger itself from threading issues.



来源:https://stackoverflow.com/questions/8621124/jpa-entitymanager-static-or-instance

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!