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.
Related
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?
I am using spring and hibernate application, In my requirement I have to load data from database at the time of project deployement and store data in Map or List for further use in whole application. I have googled a lot but not found any solution.
try using a ServletContainerInitializer
https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Application_Platform/6/html/API_Documentation/files/javadoc/javax/servlet/ServletContainerInitializer.html
If this ServletContainerInitializer is bundled in a JAR file inside the WEB-INF/lib directory of an application, its onStartup method will be invoked only once during the startup of the bundling application.
You can use
<prop key="hibernate.cache.use_query_cache">true</prop>
In hibernate configuration.xml
to cache the data that you access from data base and store in object ... now if you use the same object anywhere in your application it will use the same cache and wil not hit the database again.
Another way is
you can configure the cache using the xml file, see the spring reference manual:
http://static.springsource.org/spring/docs/current/spring-framework-reference/html/cache.html#cache-declarative-xml
<!-- the service we want to make cacheable -->
<bean id="service" class="x.y.service.MyService"/>
<!-- cache definitions -->
<cache:advice id="cacheAdvice" cache-manager="cacheManager">
<cache:caching cache="books">
<cache:cacheable method="getData" key="#id"/>
<cache:cache-evict method="loadData" all-entries="true"/>
</cache:caching>
</cache:advice>
<!-- apply the cacheable behaviour to all dataService interfaces -->
<aop:config>
<aop:advisor advice-ref="cacheAdvice" pointcut="execution(* x.y.myService.*(..))"/>
</aop:config>
Better approach is to use Hibernate, In hibernate we have First Level cache.
First-level cache always Associates with the Session object. Hibernate uses this cache by default. Here, it processes one transaction after another one, means wont process one transaction many times. Mainly it reduces the number of SQL queries it needs to generate within a given transaction. That is instead of updating after every modification done in the transaction, it updates the transaction only at the end of the transaction.
First level cache retrieval example
In this example, I am retrieving DepartmentEntity object from database using hibernate session. I will retrieve it multiple times, and will observe the sql logs to see the differences.
//Open the hibernate session
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
//fetch the department entity from database first time
DepartmentEntity department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
System.out.println(department.getName());
//fetch the department entity again
department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
System.out.println(department.getName());
session.getTransaction().commit();
HibernateUtil.shutdown();
Output:
Hibernate: select department0_.ID as ID0_0_, department0_.NAME as NAME0_0_ from DEPARTMENT department0_ where department0_.ID=?
Human Resource
Human Resource
As you can see that second “session.load()” statement does not execute select query again and load the department entity directly.
If you need to load the collection at time of class loading you can make use of immediate fetching or eager loading strategy in Hibernate. According to eager loading, when you make any collection as eagerly loaded lets suppose-->
If Foo has a Collection, and you set it to lazy, then only when you need the contents fo that collection are the selected, loaded, etc. whereas if it is eager, it will load the Bars at the time it loads Foo. This can be problematic if you eagerly load a collection of entities that eagerly load a collection of entities, and so on.
But I suppose in your case the Fetch Type = eager strategy will work and it will load at the time the class is loaded.
An Example :
#OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
#JoinColumn(name="countryId")
private Set states;
First of all you can't use any List or Map as Cache replacement. You can use Hibernate Second Level Cache, or even an external caching solution as long as your data is not going to be modified, which might cause consistency issues.
So if teh cached data is read-only then you can safely cache it. Otherwise you need a read-write cache, and the second Level Cache is much more appropriate in this scenario.
i want to configure query cache without second level cache for some learning purpose as i have read it can be done but somehow for me query cache works only with 2nd level cache.
Here is my configuration
<property name="cache.use_query_cache">true</property>
Entity class is
#Entity
public class Company {}
but when i do
session = factory.openSession();
Query getQuery=session.createQuery("from Company where companyId=1");
getQuery.setCacheable(true);
Object company2 = getQuery.uniqueResult();
session.close();
session = factory.openSession();
getQuery=session.createQuery("from Company where companyId=1");
getQuery.setCacheable(true);
company2 = getQuery.uniqueResult();
session.close();
Two separate queries are fired .
As soon as i do
#Entity
#Cacheable
#Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
public class Company {}
Query cache work but it enables the second level cache also. So how to configure query
cache without enabling second level cache?
Query cache needs the 2nd level cache to do its job, since the results of the queries are then retrieved from the 2nd level cache. The query cache just keeps track of a query and the set of ids that the query returned. These ids are then retrieved from 2nd level cache from further speed increase. Where did you read you could have query cache without 2nd level cache?
I have the following code:
Person a = new Person();
a.setName("John");
Session session = openHibernateSession();
session.beginTransaction();
session.saveOrUpdate(a);
Criteria critera = session.createCriteria(Person.class);
critera.add(Restrictions.eq("name","John"));
Person personFromCache = (Person) criteria.uniqueResult();
...
session.commit();
What I want is to have the ability to search objects from both the database and Hibernate's cache. The following example returns null upon calling uniqueResult. Is there any way to retrieve saved objects that have not yet been committed to the database?
If you are searching other than ID then Hibernate will not use first level cache. Hibernate get and load is related to first level cache by default but criteria query is not. In your case there are two solution from my side
By flushing session = Just flush your session like this session.flush(); while doing so data from session will be synchronize to database hence Id will ge generated and as result Criteria query will find the result in database and will result list to you.
Enable hibernate second level cache = You can enable second level cache by hibernate cache providers like ehCache and apply the trick.
You can use the StatelessSession but be warned:
those entitys are not bound to any session and you will get Exceptions if you like to resolve relations or lazy fields!
session.beginTransaction();
session.saveOrUpdate(a);
session.flush();
Criteria critera = session.createCriteria(Person.class);
critera.add(Restrictions.eq("name","John"));
Person personFromCache = (Person) criteria.uniqueResult();
We do some similar things except using TestNg test framework. Several of the answers discuss the session.flush() method call. This is correct. The call to flush tells Hibernate to do several things, including making sure that all database calls currently waiting in the queue get executed and cleared from the queue.
It returns data even if you are selecting on the basis of username. It is not returning null.
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)