gif animé ordinateur

mercredi 19 juin 2013

Multi-threading application issues, with JPA Hibernate

I recently worked with Hibernate JPA 2.0 in multithreading application, and have to deal and manage somme thread safe issues. So I'd like to share this post with who 'll face the same problems in his next devoloppements.

In my case, i try to develop a multi-threading standalone application in which every worker thread can make database transactions (insert or update). These transactions must not delay the thread in any case.

First of all, keep in mind that JPA EntityManager are not synchronized. That means that you cannot create an instance of EntityManager and do all the transactions from that instance. Although, JPA EntityManagerFactory is a synchronized object and hence you can create as many EntityManager you want from an instance of EntityManagerFactory.

My designed possible solution is an EntityManagerHelper class:


public class EntityManagerHelper {

    private static final EntityManagerFactory emf; 
    private static final ThreadLocal<EntityManager> threadLocal;

    static {
        emf = Persistence.createEntityManagerFactory("MyPersistanceUnit");      
        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();
    } 
}


This allows me to use the JPA trade safe object EntityManagerFactory to provide the same
JPA EntityManager instance call. 

Next is to call this EntityManagerHelper in seperate class

public class DatabaseService {  
      public static void insertEntity(AnEntity entity){  
           EntityManager em = EntityManagerHelper.getEntityManager();  
           try{  
                EntityManagerHelper.beginTransaction();  
                em.merge(entity);  
                EntityManagerHelper.commit();  
           }catch(Exception e){  
                logger.fatal("Entity Insert Exception:",e);  
                EntityManagerHelper.rollback();  
           }  
           finally{  
                EntityManagerHelper.closeEntityManager();  
           }  
      }  
      public static AnEntity findEntitybyId(int id){  
            EntityManager em = EntityManagerHelper.getEntityManager();  
           AnEntity anEntity = em.find(AnEntity.class, id);  
           EntityManagerHelper.closeEntityManager();  
           return anEntity;  
      }  
 }  

 I hope this'll help.

Aucun commentaire:

Enregistrer un commentaire