0

When I make a request to my Servlet, it checks the database for any updated Entities (I am using JPA for that). The updated Entity is then fetched and the Servlet is supposed to return the entity as a JSON String. But I am getting an old version of the entity, one that has not been updated yet – although I can see the underlying MySQL database already has the updates. How is this possible? Am I missing any buffers or caches?

This is my architecture / the data flow:

 ––––––--    timestamp of previous request   ----------–––
| client |–––––––––––––––––––––––––––––––––>| PullServlet |
 --------        (e.g. 1475056871050)        -------------
                                                   |(injected)
                                                   |
                 --------------------       ---------------
                |   Entity Facade    |<----|    remote     |
                |  implementation    |     | Entity Facade |
                 --------------------       ---------------
                          |
                 @NamedQuery
                 | SELECT m
                 | FROM MyEntity m
                 | WHERE 
                 | m.updated >=:previousRequest

Let's say the row in the MySQL database looks like this:

 id | updated       | value
 ---+---------------+--------
 12 | 0             | "hi"

Then an update is made and the updated column logs the time in milliseconds when the update was made:

 id | updated       | value
 ---+---------------+--------
 12 | 1475056872002 | "hello"

so the query SELECT ... WHERE 1475056872002 >= 1475056871050 returns the entity because the updated column¹ has a value that is greater than the previousRequest parameter.

However when I log the result of the query, I get something like this

id=12, updated=0, value="hi"

instead of

id=12, updated=1475056872002, value="hello"

And the old row gets send to my Servlet, which then sends the old version as JSON to my client:

{
  "id" : 12,
  "updated" : 0,
  "value" : "hi"
}

Question: is there any cache that I could "flush" or anything, to make sure that the selected rows are always up to date?

Update

So I added some logging and this is the result:

Facade makes update

UPDATED entity: id=45111, updated=1475067494578, value=100 

Client makes request to servlet a few seconds later

Client requested update – fetching entities  // servlet
Facade fetched update: id=45111, updated=1475066854564, value=96  // Facade
servlet received update: id=45111, updated=1475066854564, value=96 // servlet again

Client receives JSON

{
  "id": 45111,     
  "updated": 1475066854564,     
  "value": 96
}

Solution

Thanks to Navneet Arora I found out that the entites where indeed cached and the query used those cached instances instead of retrieving the entites from the database. This Answer from another question shows how ignore the cache.

Now my query looks like this:

 TypedQuery<Post> query = getEntityManager().createNamedQuery("MyEntity.getUpdatedSince", MyEntity.class);
 query.setParameter("previousRequest", previousRequest);
 query.setHint(QueryHints.REFRESH, HintValues.TRUE);  //this does the trick

And now everything is fine and I get all the updates :)

__________________
¹ the updated column and the previousRequest parameter are unix timestamps in milliseconds

Community
  • 1
  • 1
GameDroids
  • 5,338
  • 6
  • 34
  • 54

1 Answers1

1

In your calling code, you can check if your entity is available in cache or not. If it is available with older value, you can clean it using evict or evictAll method and then try to retrieve values. Following are some sample coding statements for your reference:-

javax.persistence.Cache cache = entityManagerFactory.getCache();

  System.out.println("cache.contain should return true if entity exists in cache: "+cache.contains(Order.class, order.Id())); 

With following code, you can remove entity from cache, if it exists there:

            cache.evict(Order.class);
  • Interesting! Now I get a lot of log entries like: `cache.contain should return true if entity with id 45252 exists in cache: true`. – GameDroids Sep 28 '16 at 13:09
  • Thank you, could you tell me if there is a more "general" way to remove entities from the cache, or stop caching at all? `cache.evict()` sounds quite like a rather "heavy" operation, when having to do it before every request (which is going to be a few times per second) – GameDroids Sep 28 '16 at 13:22
  • 1
    To avoid this, you can disable second level cache or can have selective caching setting in persistence.xml file. Actually we should configure L2 caching only in case of frequent read and infrequent modification because having Stale data for updated objects is the drawback of L2 caching. Following entry in persistence.xml will disable L2 caching NONE In place of NONE, if you put ENABLE_SELECTIVE as value then only those entities which are annotated as @Cacheable(true), will be cached. – Navneet Arora Sep 28 '16 at 17:32