24

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.

user1589188
  • 4,159
  • 12
  • 49
  • 99
  • Can you detail a little about your injector mechanism and how is the EntityManager instance .For example is it a spring application .Are you using OpenEntityManagerInViewFilter ? – Rohit Feb 15 '13 at 04:04
  • Yes sure. The very same EntityManager instance/object is passing around in the library but I dont see any public function for me to get it. So I used the com.google.inject.Injector to get its instance to use it in my functions. – user1589188 Feb 15 '13 at 04:20

5 Answers5

32

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();
    }
}
Makky
  • 15,166
  • 17
  • 58
  • 81
14

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

prunge
  • 20,579
  • 3
  • 71
  • 75
  • Thanks! I would love to assist your help. I found guice in the library, if thats related. Otherwise, please tell me how to find what you want to know. – user1589188 Feb 15 '13 at 04:28
  • 2
    "Each thread needs to use its own entity manager or bad things will happen." what could go wrong can you please elaborate. – eatSleepCode Sep 02 '15 at 12:03
4

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

gerrytan
  • 37,387
  • 8
  • 78
  • 91
1

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

n0rm1e
  • 3,688
  • 2
  • 23
  • 36
0

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.

John Donn
  • 1,441
  • 2
  • 15
  • 39