users@glassfish.java.net

JPA, Eclipselink, EJB and caching question

From: N W <emailnbw_at_gmail.com>
Date: Fri, 9 Sep 2011 10:06:20 -0400

Hi folk,

If this question is more suited for the Eclipselink mailing list please let me know.

I'm using GF 3.1, Eclipselink, Jersey etc. w/JDK 1.6.0_22.

I have a Jersey resource class (class A) which is also a stateless local EJB. When one of the methods on this class receives a Jersey request it makes a call to a 2nd stateless EJB which has been injected into the class with @EJB.

The method called on this injected EJB creates a new entity and persists it with entityManager.persist(). Then it enters a loop. Inside this loop it periodically updates a property on the new entity and calls entityManager.merge and entityManager.flush.


I have a second Jersey resource class (class B) which is also a local Stateless EJB. When one of the methods on this class receives a Jersey request it makes a call to a 2nd stateless EJB which has been injected to the class with @EJB. The method called on this injected EJB simply creates a TypedQuery which uses a NamedQuery which does a SELECT to fetch all of the entities of the type created by the code path I described above. It marshals these entities into JSON and sends them to the client.

Pretty simple stuff.

What I have noticed is if I make repeated calls to the second Jersey resource (class B) to retrieve the entity state I do not get back the current state but that I get back what appears to be the state of the entity the 1st time I retrieved it. For example:

call resource class B
get back entity state with property A set to 20

wait some time

call resource class B
get back entity state with property A set to 20

However I would expect the property state when I made the second call to be different then 20 because in the time I waited between calls the code path I described above in class A is updating the value of that property. In fact I can see in the logs the value is updated and merge() and flush() are called but the state that class B fetches never changes from the state it fetched the first time.

The only time this code shows the updated/current state of the object is when the code in class A completes, then when class B fetches the state it sees the property value set to 100.

This clearly has something to do with the fact that the EJB transaction is completing/committed when the method in class A completes and things are flushed at that time and how Eclipselink uses caching and the interaction between the two.

What I am guessing is that when I make the call to class B the first time Eclipselink does not have anything in its cache so it goes to the DB and gets it. Which is the value of 20 in my example. When I make subsequent calls to class B Eclipelink sees that it is already in its cache so it fetches the cached state (with property value 20). When the code in class A completes and the method ends the transaction is committed and this causes Eclipselink to either invalidate the cache or updates the state of the cached entity. Either way that is why I am seeing the correct final state.

What I am confused about is why I do not see the interim states. The code that updates the state manually calls flush() after calling merge(). Why doesn't this also update the cache values?

The only way I have been able to see this updated state is by doing one of the two following things:

1) Set the query hint "eclipse link.refresh" to true on the fetch query called by class B
2) Change the query from a NamedQuery to simple a Query, eg. TypedQuery<Foo.class> q = entityManager.createQuery vs. entityManager.createdNamedQuery.

However, doing either of these things forces a fetch from the DB which negates the in memory cache optimizations.

Any insight would be appreciated. Thanks,

-Noah