1

I am working with Hibernate 4.3.8 on a web app and It looks like that the persist() method does not update the PersistentContext (cache level 1). Here is my configuration and the singleton to manage the persistent operations:

Hibernate configuration

<persistence-unit name="PersistenceUnit" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
    <properties>
        <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
        <property name="hibernate.connection.driver_class" value="org.postgresql.Driver"/>
        <property name="hibernate.connection.url" value="jdbc:postgresql://localhost:5432/irm"/>
        <property name="hibernate.connection.username" value="nrossi"/>
        <property name="hibernate.connection.password" value="nicolas"/>
        <property name="hibernate.connection.pool_size" value="5"/>
        <property name="hibernate.show_sql" value="true"/>
        <property name="hibernate.format_sql" value="true"/>
        <property name="hibernate.max_fetch_depth" value="5"/>
        <property name="hibernate.hbm2ddl.auto" value="update"/>
    </properties>
</persistence-unit>

Persistence Manager

public class PersistenceManager
{
    private static final Logger log = LogManager.getLogger();
    private static final EntityManagerFactory emf;
    private static final ThreadLocal<EntityManager> threadLocal;

    static
    {
        emf = Persistence.createEntityManagerFactory("PersistenceUnit");
        threadLocal = new ThreadLocal<EntityManager>();
    }

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

       if (em == null)
       {
           em = emf.createEntityManager();
           threadLocal.set(em);
       }
       return em;
    }

    public static <T>T get(Class<T> clazz, Object id)
    {
       return getEntityManager().find(clazz, id);
    }

    public static void save(Object object)
    {
       EntityManager em = getEntityManager();
       EntityTransaction et = em.getTransaction();
       et.begin();
       try
       {
           em.persist(object);
           et.commit();
       }
       catch (Exception e)
       {
           et.rollback();
           throw new RuntimeException("Error saving object", e);
       }
   }
}

I update a model calling PersistenceManager.save(model) and it updates the record on the database, but after that when I call PersistenceManager.get(model.id) it returns the model from memory with the old values. It looks like the persist method is not updating the PersistenceCache.

By the way, If I call the PersistenceManager.get(model.id) on a new thread (i.e. incognito window) it returns the updated model.

I tried adding a refresh call em.refresh(model) after the commit and It is working, but I am not sure if this is the right way to get the context updated.

Updated info I coded a simple JSP page just to reproduce the behavior. If I update the entity description and wait 5' and refresh the page It returns the old value:

<%@page import="com.identicum.framework.persistence.PersistenceManager"%>
<%@page import="com.identicum.irm.core.model.Entity"%>
<%
    Entity entity = PersistenceManager.get(Entity.class, 1L);
    String value = request.getParameter("entityName");
    if(value != null)
    {
        entity.setDescription(value);
        PersistenceManager.save(entity);
    }
%>
<html>
<body>

Entity description: <b><%= entity.getDescription() %></b>

<br>
<br>

<form method="post">

    Enter new entity description <br>
    <input type="text" name="entityName"/>

    <input type="submit" />

</form>


</body>
</html>

** New information **

My PersistenceManager is a copy of this suggestion. My application is an Application-managed EntityManager. I have to access to the same EntityManager during the lifecycle of each request. That's the reason this approach. Is there any other way to implement this ?

Community
  • 1
  • 1
Nicolás Rossi
  • 153
  • 2
  • 11
  • Post all relevant code including where you are loading and updating these entities. – Alan Hay Nov 10 '16 at 20:11
  • There is a servlet which handles each request and runs the following commands: 1) To get the model: `PersistenceManager.get(Entity.class, id);` and 2) To update the model: Entity entity = PersistenceManager.get(Entity.class, id); entity.setName("B"); PersistenceManager.save(entity); And the PersistenceManager code is on the first question. – Nicolás Rossi Nov 10 '16 at 20:53
  • Hi Alan, I simplified the code and wrote a simple jsp to reproduce the behavior. You can find it [here](https://dl.dropboxusercontent.com/u/9319179/test.jsp). I found that the problem starts after a few minutes. I run the jsp and post a new description to the entity. Then I wait 5 minutes and the I run the jsp again (without parameters) and I see again the first description. – Nicolás Rossi Nov 10 '16 at 21:26

2 Answers2

0

First of all persist() is for new entities (no record on database). If you want to change an object you must use merge().

But your problem is that you probably are in a multi threaded environment. So you cannot use ThreadLocal. Each thread will have his own PersistenceManager.

What app server or web container are you using?

Simon Martinelli
  • 34,053
  • 5
  • 48
  • 82
  • It's a Tomcat App Server. But the problem is that it looks like new threads are getting the old model from the PersistentContext. I am not sure if the problem is having own PersistenceManager on each thread. In that case I can have a 'performance issue' but not a 'cache issue'. Do you agree? – Nicolás Rossi Nov 11 '16 at 16:35
  • I don't think that you will have a performance issue. In Java EE servers the PersistenceContext is bound to the Transaction. And with merge() you don't have to read the entities before updating. – Simon Martinelli Nov 11 '16 at 17:34
  • I know but the problem is still the cache when returning objects even when I use merge instead of persist – Nicolás Rossi Nov 11 '16 at 20:13
0

I finally fixed it changing the way I get and close the EntityManager. Now I get the EntityManager from the EntityManagerFactory at the beginning of each request (on my Rest Dispatcher) and close it at the end. In this way each request has his own PersistentContext.

The PersistenceMangaer.java is almost the same. The main difference is that I removed the EntityManagerFactory reference to the ApplicationServiceContext and I call the setEntityManager() outside the class. Here is an example:

PersistenceManager.setEntityManager(PersistenceFactory.createEntityManager);
FooService.createObject1();
FooService.createObject2();
PersistenceManager.closeEntityManager();

These links where helpful to find the problem:

Best practice to get EntityManagerFactory

Should JPA Entity Manager be closed?

http://www.objectdb.com/java/jpa/start/connection

Community
  • 1
  • 1
Nicolás Rossi
  • 153
  • 2
  • 11