views:

144

answers:

3

Ok, Here is my problem.

I have a table named Master_Info_tbl. Its a lookup table:

Here is the code for the table:

 @Entity
@Table(name="MASTER_INFO_T")
 public class CodeValue  implements java.io.Serializable {
 private static final long serialVersionUID = -3732397626260983394L;
 private Integer objectid;
 private String codetype;
 private String code;
 private String shortdesc;
 private String longdesc;
 private Integer dptid;
 private Integer sequen;
 private Timestamp begindate;
 private Timestamp enddate;
 private String username;
 private Timestamp rowlastchange;
 //getter Setter methods

I have a service layer which calls the method
      
service.findbycodeType("Code1");


  same way this table is queried for the other code types as well e.g. code2, code3 and so on till code10 which gets the result set from the same table and is shown into the drop down of the jsp pages since these drop downs are in 90% of the pages I am thinking to cache them globally.

Any idea how to achieve this?

FYI: I am using JPA and Hibernate with Struts2 and Spring. The database being used is DB2 UDB8.2


Please help!

A: 

Take a look at hibernate query cache feature.

You can also use some lightweight standalone caching solution, like OSCache. It gives you full control over what, when, and how is cached, but you will need to also think when to refresh the cache.

serg
I checked the link which you have provided but its not going to help me because I am using the same method and again next time I am calling the same method with different arguments(code1, code2, code3 etc.) so the previous data will be flushed automatically since its the same query only with different parameters.
Sameer Malhotra
You are right, then probably manual caching is the only option...
serg
No, the OP is not right :)
Pascal Thivent
I got another solution as follows:if (query instanceof org.hibernate.ejb.QueryImpl) { logger .info("Yes the query is of the instance org.hibernate.ejb.QueryImpl so alreaedy set the cacheable true"); ((org.hibernate.ejb.QueryImpl) query).getHibernateQuery() .setCacheable(true); }do u think it might work...
Sameer Malhotra
A: 

(...) since these drop downs are in 90% of the pages I am thinking to cache them globally.

Using the query cache would be very appropriate for this use case. So activate the second-level cache, cache the CodeValue entity (see 2.2.8. Caching entities) and put the query behind findbycodeType in the query cache. To do so, use:

javax.persistence.Query query = manager.createQuery(...);
query.setHint("org.hibernate.cacheable", true);

And to clarify, the combination of the query and the values provided as parameters to that query is used as a key, and the value is the list of identifiers for that query. Schematically, something like that:

*--------------------------------------------------------------------------*
|                              Query Cache                                 |
|--------------------------------------------------------------------------|
| [ "from CodeValue c where c.codetype=?", ["Code1"] ] -> [ 1, 2, ... ]    |
| [ "from CodeValue c where c.codetype=?", ["Code2"] ] -> [ 3, 5, 6, ... ] |
*--------------------------------------------------------------------------*

So calling your method with different arguments won't "flush previous data", the argument is part of the key (or the query cache wouldn't work).

Note that this is Hibernate specific, JPA 1.0 doesn't specify second-level cache and query caching.

See also

Pascal Thivent
As I mentioned I am using jpa with hibernate and for some reason when I try to set em.setCacheable(true); i am not able to do it.This is the entitymanger code:import javax.persistence.EntityManager;@PersistenceContext public void setEntityManager(EntityManager em) { this.em = em; }Is there any jar file I am missing?
Sameer Malhotra
I got another solution as follows: if (query instanceof org.hibernate.ejb.QueryImpl) { logger .info("Yes the query is of the instance org.hibernate.ejb.QueryImpl so alreaedy set the cacheable true"); ((org.hibernate.ejb.QueryImpl) query).getHibernateQuery() .setCacheable(true); } do u think it might work...
Sameer Malhotra
@Sameer See my update.
Pascal Thivent
@Pascal Thankyou very much for the update. I have implemented the 2nd level cache. now How do I know that the caching is working properly. I meant to say I just want to make sure that the object which I am marking as cacheable are there in the cache somewhere?
Sameer Malhotra
@Sameer Configure Hibernate to *Log all second-level cache activity*. See [this answer](http://stackoverflow.com/questions/2293866/knowing-when-hitting-database-vs-cache/2293885#2293885)
Pascal Thivent
@Pascal Please look into the new Answer I have posted and if you have any suggestion on it.
Sameer Malhotra
A: 

@Pascal
Thank you very much for all your responses. It has helped me a lot.I implemented everything what I supposed to implement(I Think). Still I dont know if the second level caching is working or not.Since I am not able to see anything in the logging in the log4j logging file from cache and also nothing is showing up in the console. In order to show that second level cache implementation is working I need to have some kind of proof and need to show it to my manager.So I am kind of stuck.
Please help!
I know I am very close to finish it up but just....
Here is my code(if you think something is missing or something should not be there please do let me know):
Entity Class

@Entity
@Cache(usage=CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
@Table(name = "CODEVALUE_T")
public class CodeValue implements java.io.Serializable {
//all the field name with getter and setter
}

Persistence.xml:

<properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.DB2Dialect" />
            <property name="hibernate.show_sql" value="false" />
            <property name="hibernate.cache.use_second_level_cache" value="true"/>
            <property name="hibernate.cache.use_query_cache" value="true"/>
            <property name="hibernate.cache.provider_class" value="org.hibernate.cache.EhCacheProvider" />
        </properties>

Service Layer DAO:

try {
            System.out.println("Calling the findByCodetype() method");
            final String queryString = "select model from CodeValue model where model.codetype"
                    + "= :propertyValue" + " order by model.code";

            Query query = em.createQuery(queryString);
            query.setHint("org.hibernate.cacheable", true);
            query.setParameter("propertyValue", propertyName);
            return query.getResultList();

        } catch (RuntimeException re) {
            logger.error("findByCodetype failed: ", re);
            throw re;
        }

Log4j.property value to show the verbose
log4j.category.org.hibernate.cache=DEBUG

ehcache.xml code(It's location is in src/ folder same place where my struts.xml file is located)

<ehcache>
   <diskStore path="java.io.tmpdir"/>
   <defaultCache
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="6000"
        timeToLiveSeconds="12000"
        overflowToDisk="true"
        diskPersistent="false"
        diskExpiryThreadIntervalSeconds="120"
        />

</ehcache>
Sameer Malhotra