0

I am new to JPA and Java. I understood how EntityManager and EMF works a littel bit. I have JPAUtill from where I get EntityManager, which is using ThreadLocal variable, which makes EntityManager thread safe. I have DAO where in I am persisting new users when having 10 thousand thread accesses simultaneously.

I get to see following exception:

javax.persistence.PersistenceException: org.hibernate.SessionException: Session is closed!
        at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:614)

Here is my DAO code

try{
    entityManager = JPAUtil.getEntityManager();
    user.setArea(getArea());
    user.setCity(getCity());
    user.setPassword("xxxxx");
    user.setEmail_Id(getEmail_Id());
    user.setMobile_Num(TempMobile_Num);
    user.setFirst_Name(getFirst_Name());
    user.setSession_Id("0");
    user.setEmail_Verification_Status("NOT VERIFIED");
    user.setBalance(new BigDecimal(0.00));
    if (!entityManager.getTransaction().isActive()){
        entityManager.getTransaction().begin();
    }
    entityManager.persist(user);
    JPAUtil.commit();
} catch (Exception e) {
    logger.info(e);
    e.printStackTrace();
} finally{
    if(entityManager.isOpen())
    JPAUtil.closeEntityManager();
}

JPAUtil:

public class JPAUtil {

    private static Logger logger = Logger.getLogger(JPAUtil.class);
    private static EntityManager entityManager = null;
    private static final ThreadLocal<EntityManager> threadLocal;

    private static EntityManagerFactory emf = null;

    static {
        try {
            emf = Persistence.createEntityManagerFactory("XYZDB");
            threadLocal = new ThreadLocal<EntityManager>();
        } catch (Throwable ex) {
            logger.info("JPAUtil Exception", ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static EntityManager getEntityManager() {
        try {
            entityManager = threadLocal.get();

            if (entityManager == null || !entityManager.isOpen()) {

                JPAUtil.entityManager = emf.createEntityManager();
                threadLocal.set(entityManager);

            } else if (!emf.isOpen()) {
                entityManager = threadLocal.get();
                emf = Persistence.createEntityManagerFactory("XYZDB");
                JPAUtil.entityManager = emf.createEntityManager();
                threadLocal.set(entityManager);
            }
        } catch (Throwable ex) {
            logger.info("JPAUtil Exception", ex);
            throw new ExceptionInInitializerError(ex);
        }
        return JPAUtil.entityManager;
    }

    public static void closeEntityManager() {
        EntityManager entityManager = threadLocal.get();
        if (entityManager != null) {
            entityManager.close();
            threadLocal.set(null);
        }
    }

    public static void closeEntityManagerFactory() {
        emf.close();
    }

    public static void commit() {
        if (!entityManager.getTransaction().isActive()) {
            entityManager.getTransaction().begin();
        }
        entityManager.getTransaction().commit();
    }

    public static void rollback() {
        if (!entityManager.getTransaction().isActive()) {
            entityManager.getTransaction().begin();
        }
        entityManager.getTransaction().rollback();
    }
}

Can someone please help me understand the issue and how to resolve it?

  • Show us the class for `user`, we need to know which types you use for Area, City, ... – Marged Jul 02 '15 at 08:52
  • @Marged String in model class and varchar in mysql.. – Gopinath Shri Jul 02 '15 at 08:55
  • and Balance is a String too ? I don´t think so. Just show the definition of the user object – Marged Jul 02 '15 at 08:58
  • I don't think this problem has anything to do with the types of Area, City, etc. But can you show the source code of `JPAUtil`? - if there is a thread safety problem, it's in there. – Erwin Bolwidt Jul 02 '15 at 09:01
  • 1
    What are you doing in `JPAUtil.closeEntityManager()`? Your `ThreadLocal` is quite senseless, when your are creating and closing an `EntityManager` in each method-call. If you are trying to reuse a closed `EntityManager` - in `JPAUtil.getEntityManager()` - this might explain your Exception. – Christopher Jul 02 '15 at 09:08
  • @ErwinBolwidt and Christopher i have added please tell me if have to change my jpautill class...:) – Gopinath Shri Jul 02 '15 at 09:38

1 Answers1

0

Remove this static variable form JPAUtil:

private static EntityManager entityManager = null;

You were still using a static variable; you didn't really use the ThreadLocal.

Change your getEntityManager to this:

public static EntityManager getEntityManager() {
    EntityManager entityManager;
    try {
        entityManager = threadLocal.get();

        if (entityManager == null || !entityManager.isOpen()) {
            entityManager = emf.createEntityManager();
            threadLocal.set(entityManager);

        }
    } catch (Throwable ex) {
        logger.info("JPAUtil Exception", ex);
        throw new ExceptionInInitializerError(ex);
    }
    return entityManager;
}
Erwin Bolwidt
  • 30,799
  • 15
  • 56
  • 79
  • Oh sorry i din't realize that and i should be adding EntityManager entityManager = threadLocal.get(); to commit(),rollback() methods right...??? – Gopinath Shri Jul 02 '15 at 09:55
  • @GopinathShri Yes you're right, you also need to fix up the other methods like you suggest – Erwin Bolwidt Jul 02 '15 at 09:57
  • thanks..for helping..so its make my JPAUtill thread safe right..?? :) – Gopinath Shri Jul 02 '15 at 10:00
  • Yes, as far as I can see that should make it safe. – Erwin Bolwidt Jul 02 '15 at 10:04
  • @GopinathShri: In the excerpt of your DAO code `entityManager#getTransaction().commit()` is never called. But afterwards in the finally block `JPAUtils.closeEntityManager()` is called. Does that work? And I still don't get the `ThreadLocal` thing. You are creating an `EntityManger`-instance every time you call your method. And in the same method the mentioned instance is closed. Why do you store it in a `ThreadLocal`? – Christopher Jul 02 '15 at 21:08
  • @Christopher it was a typpo...it don't work or persist..the entity untill unless you wont commit...coming to your 2nd question check this http://stackoverflow.com/questions/15071238/entitymanager-threadlocal-pattern-with-jpa-in-jse – Gopinath Shri Jul 03 '15 at 04:50
  • @GopinathShri `EntityManagerFactory` is thread-safe. It would be sufficent to get your `EntityManger` from that thread-safe source, residing in your `JPAUtil` class. As long as you are in one method, there is no shared state in an instance or static class. So there is no need for `ThreadLocal`. Please check http://stackoverflow.com/q/12825847/948784 – Christopher Jul 03 '15 at 06:38