JAVA: an EntityManager object in a multithread environment

后端 未结 5 1120
傲寒
傲寒 2020-12-07 16:50

if I have multiple threads, each use injector to get the EntityManager object, each use the em object to select a list of other class objects. Ready to be used in a for loop

相关标签:
5条回答
  • 2020-12-07 17:23

    There are two types of managing EntityManager: container managed and application managed. For application managed, the preferred method of obtaining EntityManager is through EntityManagerFactory. Java EE tutorial says this:

    Container-Managed Entity Managers

    With a container-managed entity manager, an EntityManager instance’s persistence context is automatically propagated by the container to all application components that use the EntityManager instance within a single Java Transaction API (JTA) transaction.

    JTA transactions usually involve calls across application components. To complete a JTA transaction, these components usually need access to a single persistence context. This occurs when an EntityManager is injected into the application components by means of the javax.persistence.PersistenceContext annotation. The persistence context is automatically propagated with the current JTA transaction, and EntityManager references that are mapped to the same persistence unit provide access to the persistence context within that transaction. By automatically propagating the persistence context, application components don’t need to pass references to EntityManager instances to each other in order to make changes within a single transaction. The Java EE container manages the lifecycle of container-managed entity managers.

    To obtain an EntityManager instance, inject the entity manager into the application component:

    @PersistenceContext 
    EntityManager em; 
    

    Application-Managed Entity Managers

    With an application-managed entity manager, on the other hand, the persistence context is not propagated to application components, and the lifecycle of EntityManager instances is managed by the application.

    Application-managed entity managers are used when applications need to access a persistence context that is not propagated with the JTA transaction across EntityManager instances in a particular persistence unit. In this case, each EntityManager creates a new, isolated persistence context. The EntityManager and its associated persistence context are created and destroyed explicitly by the application. They are also used when directly injecting EntityManager instances can’t be done because EntityManager instances are not thread-safe. EntityManagerFactory instances are thread-safe.

    http://docs.oracle.com/javaee/6/tutorial/doc/bnbqw.html

    0 讨论(0)
  • 2020-12-07 17:29

    Entity managers are not thread-safe (source Java EE 6 tutorial) and cannot be shared among threads. Each thread needs to use its own entity manager or bad things will happen, regardless of clear() or close() calls.

    But, if the injector is injecting each thread with its own entity manager then things should be OK.

    Spring and possibly other DI frameworks will inject a ThreadLocal-based proxy for a real entity manager into your beans. Calls that each thread makes will proxy to the real thread-local instance of an entity manager - this is how things can work even though it might appear an entity manager is shared among multiple threads.

    More details about how your entity manager is injected would help (Spring, etc.)

    0 讨论(0)
  • 2020-12-07 17:30

    Here is full working thread-safe Entity Manager Helper.

    import javax.persistence.EntityManager;
    import javax.persistence.EntityManagerFactory;
    import javax.persistence.Persistence;
    
    public class EntityManagerHelper {
    
        private static final EntityManagerFactory emf;
        private static final ThreadLocal<EntityManager> threadLocal;
    
        static {
            emf = Persistence.createEntityManagerFactory("Persistent_Name");
            threadLocal = new ThreadLocal<EntityManager>();
        }
    
        public static EntityManager getEntityManager() {
            EntityManager em = threadLocal.get();
    
            if (em == null) {
                em = emf.createEntityManager();
                // set your flush mode here
                threadLocal.set(em);
            }
            return em;
        }
    
        public static void closeEntityManager() {
            EntityManager em = threadLocal.get();
            if (em != null) {
                em.close();
                threadLocal.set(null);
            }
        }
    
        public static void closeEntityManagerFactory() {
            emf.close();
        }
    
        public static void beginTransaction() {
            getEntityManager().getTransaction().begin();
        }
    
        public static void rollback() {
            getEntityManager().getTransaction().rollback();
        }
    
        public static void commit() {
            getEntityManager().getTransaction().commit();
        }
    }
    
    0 讨论(0)
  • 2020-12-07 17:36

    You normally have transactions around what you do with database objects. What each given thread sees about the changes made by other threads is controlled by 'transaction isolation' settings.

    Start learning about different isolation settings and apply the right setting according to your needs. There is a trade-off between accuracy and speed. http://en.wikipedia.org/wiki/Isolation_%28database_systems%29

    0 讨论(0)
  • 2020-12-07 17:45

    I am off by three years or so :), but as far as injecting EntityManager in EJBs is concerned, here is a link to Adam Bien's blog entry http://www.adam-bien.com/roller/abien/entry/is_in_an_ejb_injected

    copying-pasting from there:

    "You can inject EntityManager directly into EJBs. But: is it thread safe?:

    @Stateless
    public class BookServiceBean implements BookService {
    
    
      @PersistenceContext EntityManager em;
    
      public void create(Book book) { this.em.persist(book);}
    
     }
    

    "

    and the answer is, again copying-pasting:

    "Working with EJBs without any further configuration is thread-safe regardless whether you are invoking one method or multiple methods concurrently. The container cares about the serialization of calls.",

    which perhaps could be clearer, but it implies that you can inject EntityManager in stateless session beans, and not be worried by EntityManager concurrency issues.

    0 讨论(0)
提交回复
热议问题