OpenJpa query caching is not refreshing in case of null value - java

I am facing some problem in OpenJpa second level caching. Most of times caching is working but in one particular case it is not working. Here is a scenario when it is not working,
When your code result null value then it store it into cache and then it never clear that value. Although it clears values only when query returns a value.
Here is code which I had written to get value from database,
List<PartnerapiworkflowEntity> partnerapiworkflowEntityList = null;
try {
partnerapiworkflowEntityList = entityManager.createQuery("select p from someentity p where p.id = :Id and p.name = :name and " +
"p.code = :Code and p.operationname = :operationName")
.setParameter("Id", Id)
.setParameter("name", name)
.setParameter("code", Code)
.setParameter("operationName", operationName).getResultList();//.getSingleResult();
if(partnerapiworkflowEntityList != null && partnerapiworkflowEntityList.size() > 0){
return Boolean.TRUE;
}
} catch (NoResultException ne) {
logger.severe("some logging info.");
}
finally {
// entityManager.detach(partnerapiworkflowEntity);
}
And here is a code which refresh cache.
try{
entityManager.flush();
entityManager.clear();
entityManager.getEntityManagerFactory().getCache().evictAll();
//((JpaEntityManager)entityManager.getDelegate()).getServerSession().getIdentityMapAccessor().invalidateAll();
entityManager.flush();
} catch (Exception e){
throw e;
}
And this is persistence.xml code
<property name="openjpa.jdbc.DBDictionary" value="mysql"/>
<property name="openjpa.DataCache" value="true(EnableStatistics=true, CacheSize=10000, SoftReferenceSize=0, EvictionSchedule='+10')"/>
<property name="openjpa.QueryCache" value="true(EvictPolicy='timestamp')"/>
<!--<property name="openjpa.jdbc.QuerySQLCache" value="true(EnableStatistics=true)"/>-->
<property name="javax.persistence.sharedCache.mode" value="ENABLE_SELECTIVE"/>
<property name="openjpa.Instrumentation" value="jmx(Instrument='DataCache,QueryCache,QuerySQLCache')"/>
<property name="openjpa.MetaDataRepository" value="Preload=true"/>
<property name="openjpa.Log" value="SQL=Trace" />
<property name="openjpa.ConnectionFactoryProperties" value="PrintParameters=true" />
Everything working fine when query always returns value. The problem is start when it return null value. Then first time is store in cache and then it never refresh.
I am using OpenJpa2 and Hibernate.

This issue was first observed with OpenJPA 2.2.2. Looking up online revealed that there was a defect that was fixed on trunk that was related to L2 cache (https://issues.apache.org/jira/browse/OPENJPA-2285)
But this problem is again found later in https://issues.apache.org/jira/browse/OPENJPA-2522
Solution:
So far it is not fixed yet. But they have given some bypassing solution.
Disable query cache
To disable the query cache (default), set the openjpa.QueryCache property to false:
<property name="openjpa.QueryCache" value="false"/>
By configuring sql query cache to false
To specify a custom cache class:
<property name="openjpa.jdbc.QuerySQLCache" value="com.mycompany.MyCustomCache"/>
To use an unmanaged cache:
<property name="openjpa.jdbc.QuerySQLCache" value="false"/>
OR
To use an unmanaged cache:
<property name="openjpa.jdbc.QuerySQLCache" value="all"/>
Open JPA - L2 Cache Issue and Workaround
This tutorial depicts your problem same to same. Here you can get the
clear conception of occuring this error.
It gives a solution that you must have to keep related data. So that NullPointerException will not arise. Data must be consistent until OpenJPA not solve the issue. :D
Several mechanisms are available to the application to bypass SQL
caching for a JPQL query.
A user application can disable Prepared SQL Cache for entire lifetime of a persistence context by invoking the following method on OpenJPA's EntityManager SPI interface:
OpenJPAEntityManagerSPI.setQuerySQLCache(boolean)
Plug-in property openjpa.jdbc.QuerySQLCache can be configured to
exclude certain JPQL queries as shown below.
<property name="openjpa.jdbc.QuerySQLCache" value="true(excludes='select c from Company c;select d from Department d')"/>
will never cache JPQL queries select c from Company c and select d from Department d.
Root Cause Analysis:
The query cache stores the object IDs that are returned by query executions. When you run a query, JPA assembles a key that is based on the query properties and the parameters that are used at launch time and checks for a cached query result. If one is found, the object IDs in the cached result are looked up, and the resulting persistence-capable objects are returned. Otherwise, the query is launched against the database and the object IDs that are loaded by the query are placed into the cache. The object ID list is not cached until the list that is returned at query launch time is fully traversed.
IBM Recommendation:
L2 caching increases the memory consumption of the application,
therefore, it is important to limit the size of the L2 cache. There is
also a possibility of stale data for updated objects in a clustered
environment. Configure L2 caching for read-mostly, infrequently
modified entities. L2 caches are not recommended for frequently and
concurrently updated entities.
Resource Link:
Open JPA 2.4.0 Caching Reference Guide

You are evicting entries, but what about query cache? It can be that in normal case evicting is noticed by query case, so the result is invalidated... It can explain why null fails here. Can you please confirm?
EDIT:
<property name="openjpa.QueryCache" value="false"/>
Means no query cache. My bad.
Other try - NULL check? You have query, with params - can you execute it directly on the database?

Related

Wildfly/Hibernate query result fails to return persisted entity

With Wildfly 16, using the EntityManager I persist a new entity and invoke another routine to perform an HQL query to retrieve that entity, but it fails to return.
This is running server side and is normally triggered by a client command. The command should cause the new object to be persisted, then call a routine used in several places that selects objects (like and including the newly persisted one) and format and push them to subscribers.
I've tried a few things to get this working:
Flush the EntityManager prior to the HQL query
Reuse the EntityManager via the invoked routine (with and without flushing post persist())
The only way I've managed to get the desired results is to cause the initial client command to persist the entity, then perform a second client command to retrieve the entity persisted via the first command. This is not an issue with the HQL retrieving the data as it does work - it just doesn't work immediately after persisting the entity. It seems like either the data isn't persisted prior to the HQL query or the HQL query is looking at something cached (although I haven't specifically set anything like that, so it would have to be a default I'm unaware of).
An example of the three routines:
//Routine A - calls B & C
routineB();
routineC();
//Routine B
EntityManager em = emProvider.getEntityManager(); //pulls em from a stateless bean tagged #PersistenceContext
Blah blah = new Blah();
em.persist(blah);
em.flush();
//Routine C
EntityManager em = emProvider.getEntityManager();
List<Blah> blahs = em.createNamedQuery("retrieveBlah").getResultList();
//do some stuff with blahs... except it's missing blah from Routine A
My persistence.xml settings JIC that's relevant
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQL94Dialect" />
<property name="hibernate.connection.useUnicode" value="true" />
<property name="hibernate.connection.characterEncoding" value="UTF-8" />
<property name="hibernate.connection.charSet" value="UTF-8" />
<property name="hibernate.id.new_generator_mappings" value="true" />
I need to be able to persist and retrieve the persisted via HQL query as the result of a single client command.
It turns out the post above was missing the key bit of information to resolve the issue. After posting this I continued testing and discovered the piece I overlooked, "routineB()" was marked #Asynchronous. So it was executing in parallel to routineC().

How to mark entites as cacheable

I have java jar library with JPA entities, spring repositories and spring services and now i included this library in project where i want some entities to be cacheable (cached in second level cache) and don't want to change library.
Is is possible to configure Cachemanager to include entities which are not market as #Cacheable?
If you have control over the persistence.xml, you can add
<shared-cache-mode>ALL</shared-cache-mode>
for a persistence unit to cache alle entities or
<shared-cache-mode>DISABLE_SELECTIVE</shared-cache-mode>
to enable caching for all entities but the ones you marked as #Cacheable(false) (see also https://docs.oracle.com/javaee/7/api/javax/persistence/SharedCacheMode.html)
If you want to use Hibernate's session-independent second level cache which can be used by multiple Hibernate Session you must first activate it.
First modify persistence.xml, so add:
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
and property:
<property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.EhCacheRegionFactory"/>
You can choose between ALL to cache all entities, NONE to don't cache any entities, ENABLE SELECTIVE to select the entities that will be cached and DISABLE SELECTIVE to select the entities that will not be cached. Prefer ENABLE SELECTIVE because it requires you to explicitly decide which entities are cached.
Annotate your entity with JPA #Cacheable or Hibernate #Cache annotation.
You can also use the #Cacheable (false) annotation to exclude an entity from caching if you use shared cache mode DISABLE SELECTIVE.
Hibernate doesn't use the second-level cache with JPQL or criteria queries.
If you want to use query caching modify persistence.xml, so add properties:
<property name="hibernate.cache.use_query_cache" value="true"/>
<property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.EhCacheRegionFactory"/>
and activate caching for query with setCacheable(boolean b); method, (eg.) :
Session s = (Session) em.getDelegate();
Query q = s.createQuery("SELECT b FROM Book b WHERE id = :id");
q.setParameter("id", 1L);
q.setCacheable(true);
Book b = q.uniqueResult();
Hibernate now stores the result of this query in the query cache. When your next use case executes this query, Hibernate checks if the query cache contains a result for the given parameter values. If the cache contains a matching record, Hibernate gets the query result from there. Otherwise, it executes the query and store its result in the cache.

Query cache not working

I am using Hibernate 3.2.5 for my application. I am trying to implement Query Cache but it is not working.
Problem Description:
For the first time, the DB is hit, data is fetched and cached. For the second time, for the same query again the DB is hit rather than taking the data from the cache. For the second time, I want it to take it from the cache rather than hitting the DB again.
For enabling the Query Cache, I made the below entries in the cfg.xml file:
<property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
<property name="hibernate.cache.use_query_cache">true</property>
<property name="hibernate.cache.use_second_level_cache">true</property>
Created the file: ehcache.xml and added the below entry in the hbm.xml files:
<cache usage="read-only" />
Below is the code I tried:
SessionFactory sf = new Configuration().configure("trial.cfg.xml").buildSessionFactory();
Session session = sf.openSession();
List departments1 = session.createQuery("from Dept dept where dept.deptId = 1")
.setCacheable(true)
.setCacheRegion("departmentId")
.list();
//Some business operations
session.flush();
session.close();
//Some business operations
Session session1 = sf.openSession();
List departments2 = session1.createQuery("from Dept dept where dept.deptId = 1").list();
//In the above line again it is hitting the DB rather than taking it from the cache.
I believe that I am missing something for which it is not fetching the data from the cache and hence hitting the DB. Kindly let me know how to make this Query Cache work.
The second query is not cacheable, so it doesn't use the cache. As simple as that.
Note that if this is your real code, you should simple use session.get(Dept.class, 1) to get the department.

how to disable cache in eclipselink

I have tried disabling L2 cache in EclipseLink with Eclipse indigo by using following properties in persistence.xml:-
<property name="eclipselink.cache.shared.default" value="false"/>
<shared-cache-mode>NONE</shared-cache-mode>
Basically I am testing one scenario whether same object created in two different sessions is hitting database twice or both sessions are referring to same object created in earlier session in memory cache. It should not because L2 cache is disabled by mentioning above properties in persistence.xml
My code is as below:-
Session session = DataAccessManager.getManager().openSession();
ReferenceObjectRepository referenceObjectRepository = ReferenceObjectRepository.getInstance();
ReferenceObjectKey referenceObjectKey = new ReferenceObjectKey(getStringValue("testCacheByPass.input"));
//load object first time.
ReferenceObject referenceObject = referenceObjectRepository.load(ReferenceObject.class, referenceObjectKey);
logger.log(Level.SEVERE, "Cache ReferenceObject: " + referenceObject);
//load object in another session
Session sessionNew = DataAccessManager.getManager().openNewSession();
Object dbObject = referenceObjectRepository.load(ReferenceObject.class, referenceObjectKey);
logger.log(Level.SEVERE, "DB loaded ReferenceObject: " + dbObject);
Please help me whether I have missed something? or do I need to do it some other way??
Add this line in each function where the call is made. I use in the find function when consulted a view.
((JpaEntityManager)em.getDelegate()).getServerSession().getIdentityMapAccessor().invalidateAll();
This line clear the cache before run de query.
public Entity find(Object id) {
((JpaEntityManager)em.getDelegate()).getServerSession().getIdentityMapAccessor().invalidateAll();
return em.find(Entity.class, id);
}
You have disabled the object cache, but I think you still have query cache in play. You should be able to disable query cache too with
<property name="eclipselink.query-results-cache" value="false"/>
<property name="eclipselink.refresh" value="true"/>
Same thing can be set with query hints, too. You could also try using query hints if persistence.xml configuration doesn't seem to be working.
Also note that essentially, even without the caching, you'd be comparing the same object, so unless it is detached it should be the same.
Related questions:
Disable eclipselink caching and query caching - not working?
Disable caching in JPA (eclipselink)

Hibernate: get persisted state of dirty entity

Taking following code:
MyEntity e = dao.getEntity(1);
e.setProp1(someVal);
e.setProp2(otherVal);
MyEntity eOld = dao.getEntity(1);
If I do it like this then e will get updated (because Hibernate detected it is dirty) and eOld will have the same property values (prop1, prop2) a e. Is there a way to get the persisted state of this dirty entity (as it is in the database)?
Try:
<property name="defaultAutoCommit" value="false" />
Or alternative use detach and re-attach when ready to persist.
dao.detach(e);
...
e.setProp1("AnotherVal"); //not propatated to the database
dao.merge(cat); // update
Actually I may already have found the solution myself...
I had already tried evicting eOld but that doesn't make since, I need to evict e before retrieving eOld and after the compare (for auditing) reattach (merge) e to the session again.
It seems to work in any case.

Categories