views:

90

answers:

4

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

I created a static variable for EntityManagerFactory and Intialized 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 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 point me to the right resources.

+1  A: 

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

That help?

Brad
What difference does that make? I'll give it a try.
Vanchinathan Chandrasekaran
This will add an object lock on the factoryLockObject and cause any other threads wanting to access it to wait until the lock is lifted (at the final curly brace).http://csharpindepth.com/Articles/General/Singleton.aspx
Brad
Still, will it not block the threads? If Persistence.createEntityManagerFactory("example"); is thread safe, then I dont need to synchronize it.
Vanchinathan Chandrasekaran
I don't know whether Persistence is internally thread-safe. The locking that I've shown WILL cause any threads wanting to execute this block of code to wait until the first thread is done with it. This is why your IF has to go inside the lock too.
Brad
+4  A: 

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.

Pascal Thivent
I did that before. But, some people feel that its not a good practice to initialize in the static blocks. Is that right?
Vanchinathan Chandrasekaran
@Vanchinathan That's really a typical approach when you're not in a managed environment and I don't see anything wrong with it. Now, if you provide some arguments against it, we could discuss them but until then, I maintain this recommendation.
Pascal Thivent
@Pascal,The one argument that I always get is , having code in the static blocks, hinders testing. We follow Test Driven development strictly. So I need something that is also easier to test.
Vanchinathan Chandrasekaran
@Vanchinathan Still, you want to initialize the EMF only once which is why the above pattern is used. You should then use this code to obtain an EntityManager and inject it in the classes that need it (and those will be nicely testable).
Pascal Thivent
+1  A: 

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.

erickson
A: 

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

Rajesh John