PersistenceContext bypassed by EntityManager.find() [message #1336741] |
Tue, 06 May 2014 10:49  |
Eclipse User |
|
|
|
Hi,
We are using eclipselink 2.5.1 in our application. In one case the EntityManager.lock() method is used for synchronizing on a heavily used object. We have enabled the second level cache for all objects. Now, what seems to happen is that a thread that is waiting in the lock() method, sometimes gets stale data after obtaining the lock.
What we think might be happening is that data is retrieved from the second level cache after the lock is obtained. Now we do want to have second level caching enabled as much as possible, but in these cases with locking we would like to disable the second level cache after the lock has been acquired.
We are currently doing this using
em().setProperty("javax.persistence.cache.retrieveMode", CacheRetrieveMode.BYPASS)
(where em() returns the entity manager).
This is supposed to bypass the second level cache for all find operations so in that case we should not be getting stale data but current data from the first level cache (persistence context), and if not present there from the database.
However, we are now seeing some surprising behavior, which is that immediately after doing a persist of an entity such as
id = ... // determine primary key
T object = new T();
object.setId(id);
em().persist(object);
Then an em().find() operation is returning null.
T retrieved = em().find(T.class, id());
Only if we do a flush() right after the persist(), then we get the correct entity.
This is confusing since, if I read the specs correctly, the CacheRetrieveMode should bypass only the second level cache. Strangely enough, it looks like the persistence context is also being bypassed.
What could be wrong here?
The persistence XML is attached. Note that it is a 1.0 persistence XML which is required since we are (still) deploying on an old application server (JBoss 5.1).
Cheers
Erik
[Updated on: Thu, 08 May 2014 03:04] by Moderator
|
|
|
|
Re: Locking and caching [message #1340925 is a reply to message #1336767] |
Thu, 08 May 2014 04:33  |
Eclipse User |
|
|
|
I have done some debugging and what I see happening is that the CacheRetrieveMode=BYPASS setting is being processed in QueryHintsHandler.CacheRetrieveModeHint.applyToDatabaseQuery()
if (query.isObjectLevelReadQuery()) {
if (valueToApply.equals(CacheRetrieveMode.BYPASS) || valueToApply.equals(CacheRetrieveMode.BYPASS.name())) {
query.retrieveBypassCache();
}
// CacheRetrieveMode.USE will use the EclipseLink default of
// shouldCheckDescriptorForCacheUsage which in most cases is CheckCacheByPrimaryKey.
} else {
throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)}));
}
Now, subsequenlty, when doing the find() operation, the cache is bypassed completely in ReadObjectQuery.checkEarlyReturnLocal(),
if (shouldCheckCache() && shouldMaintainCache() && (!shouldRefreshIdentityMapResult() && (!shouldRetrieveBypassCache()))
&& (!(session.isRemoteSession() && (shouldRefreshRemoteIdentityMapResult() || this.descriptor.shouldDisableCacheHitsOnRemote())))
&& (!(shouldCheckDescriptorForCacheUsage() && this.descriptor.shouldDisableCacheHits())) && (!this.descriptor.isDescriptorForInterface())) {
Object cachedObject = getQueryMechanism().checkCacheForObject(translationRow, session);
...
}
Here shouldRetrieveBypass is set to true by the query.retrieveBypassCache() hint.
|
|
|
Powered by
FUDForum. Page generated in 0.07565 seconds