开发者

How to create a thread safe EntityManagerFactory?

I'm working on an application that needs to do some database operations.

I created a static variable for EntityManagerFactory and initializeded it in the method that gets called by the application

 if (emf == null) {
      emf = Persistence.createEntityManagerFactory("example");
 }

 try {
      em 开发者_运维技巧= emf.createEntityManager();
 } catch (Exception ex) {
      logger.error(ex.getMessage());
 }

Is this thread-safe? If I create the EntityManagerFactory in a synchronized block, the number of the waiting threads increases and crashes the application.

I looked at the docs to see whether the Persistence.createEntityManagerFactory is thread-safe without any success.

Please direct me to the right resources.


An easy way to "solve" this would be to use a helper class (a la HibernateUtil) and to initialize the EntityManagerFactory in a static initialization block. Something like this:

public class JpaUtil { 
    private static final EntityManagerFactory emf;

    static {
        try {
            factory = Persistence.createEntityManagerFactory("MyPu");
        } catch (Throwable ex) {
            logger.error("Initial SessionFactory creation failed", ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

   ...

}

And the "problem" is gone.


I am not seeing any issues with the static block approach. Or you can do the same in the below manner which is a Singleton pattern with double-lock check

public class JPAHelper {

 private static JPAHelper myHelper = new JPAHelper();
 private static EntityManagerFactory myFactory = null;

 /**
  * Private constructor. Implementing synchronization with double-lock check
  */
 private JPAHelper() {

  if(myFactory == null) {
   synchronized (JPAHelper.class) {

    // This second check will be true only for the first thread entering the block incase 
    // of thread race
    if(myFactory == null) {
     myFactory = Persistence.createEntityManagerFactory("MyUnit");
    }
   }
  }
 }

 /**
  * Static Accessor Method
  * @return
  */
 public static JPAHelper getInstance() {
  if(myHelper == null) {
   myHelper = new JPAHelper();
  }
  return myHelper;
 }


 public EntityManagerFactory getJPAFactory() {
  return myFactory;
 }

And you will call

EntityManager myManager = JPAhelper.getInstance().getJPAFactory().createEntityManager();


Whether createEntityManagerFactory() is thread-safe or not, you need some strategy so that it is invoked only once. In other words, that question is irrelevant, because you must ensure that only one thread calls it.

If simply waiting for another thread to create the factory crashes your application, what will happen when every thread creates its own, clobbering the work of other threads in the process?

The code you show should be inside a synchronized block, or it is not thread safe.


You need to put locks on an object when you are creating the emf. You can put the locks on the emf object itself, but that's not best practice. Create another object:

private object factoryLockObject = new object();

and put your locks on it while creating the factory

lock(factoryLockObject) {
   if (emf == null) {
      emf = Persistence.createEntityManagerFactory("example");
   }
}

Does that help?


The answer to the question is: YES, createEntityManagerFactory() is thread-safe based on the class documentation, source and real-world application results.

The Singleton Pattern answer is most correct for avoiding an additional call to retrieve the one factory handle efficiently but note there is no need for a double-check lock as commented earlier.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜