JAVA: an EntityManager object in a multithread environment

霸气de小男生 提交于 2019-12-17 17:32:06

问题


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.

If a thread finishes first and calls clear(), will that affect the other threads? Like the for loop will have exception?

How about close()?

If the answer is "It depends", what (class definition? method call?) and where (java code? annotation? xml?) should I look at to find out how is it depended?

I did not write the source, I am just using someone else's library without documentation.

Thank you.


回答1:


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();
    }
}



回答2:


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.)




回答3:


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




回答4:


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




回答5:


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.



来源:https://stackoverflow.com/questions/14888040/java-an-entitymanager-object-in-a-multithread-environment

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