Reputation: 253
I'm trying to build cache coordination with eclipselink and here is the issue. There is a table in db which have NAME and CHECK_TIME columns. My first application have FULL cache and with getAll() it loads all values to cache from DB in the begining. After that prints objects with get("name_"+i)
in loop as [name_1,2014-07-04 00:00:00],[name_2,2014-07-04 00:00:00]
and so on .
There is a second application which are using same cache, thanks to cache coordination, and update CHECK_TIME values with merge() and I can see these new values in db. So this second app check a line in each second and update CHECK_TIME column.
After second application is starting, first application prints still old CHECK_TIME values even rmi log says objects are merged. So I think that cache coordination is not working at first, however, if I tried to create a new object with persist() like [new_name_1,2014-07-04 16:43:32]
in second app, then first application printed it to screen immediately that means cache is refreshed correctly.
Do you know why get('name_'+i)
return always old value even cache is refreshed? It is like there is a secondary cache in eclipselink.
persistence.xml
<property name="eclipselink.cache.coordination.protocol" value="rmi" />
<property name="eclipselink.cache.coordination.naming-service" value="rmi" />
<property name="eclipselink.cache.coordination.rmi.url" value="rmi://$HOST:1090" />
Subsciber.java
@NamedQueries({
@NamedQuery(name = "get", query = "select b from Subscriber b where b.name = :name ", hints = {
@QueryHint(name = QueryHints.QUERY_TYPE, value = QueryType.ReadObject),
@QueryHint(name = QueryHints.CACHE_USAGE, value = CacheUsage.CheckCacheOnly)}),
@NamedQuery(name = "getAll", query = "select b from Subscriber b ", hints = {
@QueryHint(name = QueryHints.QUERY_TYPE, value = QueryType.ReadAll),
@QueryHint(name = QueryHints.CACHE_USAGE, value = CacheUsage.DoNotCheckCache)})})
@Cache(type = CacheType.FULL, coordinationType = CacheCoordinationType.SEND_NEW_OBJECTS_WITH_CHANGES)
Edit:
private SubscriberIdentity get(String name) {
SubscriberIdentity result = null;
try {
//entityManager is global
Query query = entityManager.createNamedQuery("get");
query.setParameter("name", name);
result = (SubscriberIdentity) query.getSingleResult();
} catch (Exception e) {
if (e.getCause() instanceof NoResultException || e instanceof NoResultException) {
//TODO
}
}
return result;
}
Upvotes: 1
Views: 976
Reputation: 8935
As @Chris said, and you can also check the document EL Cache:
By default EclipseLink uses a shared object cache, that caches a subset of all objects read and persisted for the persistence unit. The EclipseLink shared cache differs from the local EntityManager cache. The shared cache exists for the duration of the persistence unit (EntityManagerFactory, or server) and is shared by all EntityManagers and users of the persistence unit. The local EntityManager cache is not shared, and only exists for the duration of the EntityManager or transaction.
The limitation of the shared cache, is that if the database is changed directly through JDBC, or by another application or server, the objects in the shared cache will be stale.
EclipseLink offers several mechanism to deal with stale data including:
Upvotes: 0
Reputation: 253
With @Chris big help in comments, I understand that the problem is using static entityManager object because it use own cache instead of checking shared cache in case of second call for get(name_1). So I changed
Query query = entityManager.createNamedQuery("get");
part as
EntityManager em = new EntityManager();
Query query = em.createNamedQuery("get");
in getter and cache coordination works truely for UPDATE case too.
Upvotes: 1