Showing posts with label Hibernate. Show all posts
Showing posts with label Hibernate. Show all posts

Monday, June 17, 2013

34 - Using-Query-Cache

In this tutorial, we'll learn how to cache results that are fetched from the Query object.

Suppost we pull data using query.

Session session = sessionFactory.openSession();
session.beginTransaction();
Query query = session.createQuery("from UserDetails user where user.userId = 1");
query.setCacheable(true);
List users = query.list();
session.getTransaction().commit();
session.close();


Session session2 = sessionFactory.openSession();
session2.beginTransaction();
Query query2 = session2.createQuery("from UserDetails user where user.userId = 1");
query2.setCacheable(true);
users = query2.list();
session2.getTransaction().commit();
session2.close();

Above code run two select quries, to overcome this we need to write query cache property.
<property name="cache.use_query_cache">true</property>

In order to make query cachable we need to tell hibernate to cache using below statement.
query.setCacheable(true);

HibernateTest.java
package org.yash.hibernate;

import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateTest {

      public static void main(String args[]) {
           
            SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
            Session session = sessionFactory.openSession();
            session.beginTransaction();

            Query query = session.createQuery("from UserDetails user where user.userId = 1");
            query.setCacheable(true);
            List users = query.list();

            session.getTransaction().commit();
            session.close();
           
           
            Session session2 = sessionFactory.openSession();
            session2.beginTransaction();

            Query query2 = session2.createQuery("from UserDetails user where user.userId = 1");
            query2.setCacheable(true);
            users = query2.list();


            session2.getTransaction().commit();
            session2.close();



      }
}

UserDetails.java
package org.yash.dto;

import java.util.ArrayList;
import java.util.Collection;

import javax.persistence.Cacheable;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;

import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;

@Entity
@Cacheable
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
@NamedQuery(name="UserDetails.byId", query="from UserDetails where userId = ?") //HQL query - based on class name
@org.hibernate.annotations.Entity(selectBeforeUpdate=true)
public class UserDetails {
      /* @Id says "userId" is primary key */
      @Id @GeneratedValue (strategy=GenerationType.AUTO)
      private int userId;    
      private String userName;
      @OneToMany(cascade=CascadeType.PERSIST)
      private Collection<Vehicle> vehicle = new ArrayList<Vehicle>();
           
      public int getUserId() {
            return userId;
      }
      public void setUserId(int userId) {
            this.userId = userId;
      }
      public String getUserName() {
            return userName;
      }
      public void setUserName(String userName) {
            this.userName = userName;
      }
      public void setVehicle(Collection<Vehicle> vehicle) {
            this.vehicle = vehicle;
      }
      public Collection<Vehicle> getVehicle() {
            return vehicle;
      }
}

hibernate.cfg.xml
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

    <session-factory>

        <property name="connection.driver_class">
            org.postgresql.Driver
        </property>
        <property name="connection.url">
            jdbc:postgresql://localhost:5433/hibernatedb
        </property>
        <property name="connection.username">postgres</property>
        <property name="connection.password">admin</property>

        <!-- JDBC connection pool (use the built-in) -->
        <property name="connection.pool_size">1</property>

        <!-- SQL dialect -->
        <property name="dialect">
            org.hibernate.dialect.PostgreSQLDialect
        </property>

            <!-- Second level cache provider -->
            <property name="cache.use_second_level_cache">true</property>
            <property name="cache.use_query_cache">true</property>
            <property name="hibernate.cache.region.factory_class">
org.hibernate.cache.ehcache.EhCacheRegionFactory
</property>

        <!-- Enable Hibernate's automatic session context management -->
        <property name="current_session_context_class">thread</property>
       
        <!-- Echo all executed SQL to stdout -->
        <property name="show_sql">true</property>
       
        <!-- Drop and re-create the database schema on startup -->
            <property name="hbm2ddl.auto">update</property> 
<!-- create / update -->
   
          <!-- Names the annotated entity class -->
            <mapping class="org.yash.dto.UserDetails"/>    
            <mapping class="org.yash.dto.Vehicle"/>  
            <mapping class="org.yash.dto.TwoWheeler"/>     
            <mapping class="org.yash.dto.FourWheeler"/>    
           
    </session-factory>

</hibernate-configuration>

33 - Configuring-Second-Level-Cache

We'll configure EHCache as our second level cache, and then put it to work. We'll fetch an object across two sessions, and we'll see how Hibernate's second level cache comes into play to save a database query.

By default second level cache is off in hibernate, we need to tell explicitly to on second level cache using below property
<property name="cache.use_second_level_cache">true</property>

This property set the cache provider
<property name="hibernate.cache.region.factory_class">
org.hibernate.cache.ehcache.EhCacheRegionFactory
</property>

Second level configuration is required which is done at Entity level, not all the Entities are enabled for default cache.
It can be done using below code.
@Entity.
@Cacheable
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE or READ_ONLY) //it defines the caching strategy

HibernateTest.java
package org.yash.hibernate;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.yash.dto.UserDetails;

public class HibernateTest {

      public static void main(String args[]) {
           
            SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
            Session session = sessionFactory.openSession();
            session.beginTransaction();

            UserDetails user = (UserDetails) session.get(UserDetails.class, 11);

            session.getTransaction().commit();
            session.close();
           
           
            session = sessionFactory.openSession();
            session.beginTransaction();

            UserDetails user2 = (UserDetails) session.get(UserDetails.class, 11);

            session.getTransaction().commit();
            session.close();



      }
}

UserDetails.java
package org.yash.dto;

import java.util.ArrayList;
import java.util.Collection;

import javax.persistence.Cacheable;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;

import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;

@Entity
@Cacheable
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
@NamedQuery(name="UserDetails.byId", query="from UserDetails where userId = ?") //HQL query - based on class name
@org.hibernate.annotations.Entity(selectBeforeUpdate=true)
public class UserDetails {
      /* @Id says "userId" is primary key */
      @Id @GeneratedValue (strategy=GenerationType.AUTO)
      private int userId;    
      private String userName;
           
      public int getUserId() {
            return userId;
      }
      public void setUserId(int userId) {
            this.userId = userId;
      }
      public String getUserName() {
            return userName;
      }
      public void setUserName(String userName) {
            this.userName = userName;
      }

}

hibernate.cfg.xml
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

    <session-factory>

        <property name="connection.driver_class">
            org.postgresql.Driver
        </property>
        <property name="connection.url">
            jdbc:postgresql://localhost:5433/hibernatedb
        </property>
        <property name="connection.username">postgres</property>
        <property name="connection.password">admin</property>

        <!-- JDBC connection pool (use the built-in) -->
        <property name="connection.pool_size">1</property>

        <!-- SQL dialect -->
        <property name="dialect">
            org.hibernate.dialect.PostgreSQLDialect
        </property>

            <!-- Second level cache provider -->
            <property name="cache.use_second_level_cache">true</property>
            <property name="hibernate.cache.region.factory_class">
org.hibernate.cache.ehcache.EhCacheRegionFactory
</property>

        <!-- Enable Hibernate's automatic session context management -->
        <property name="current_session_context_class">thread</property>
       
        <!-- Echo all executed SQL to stdout -->
        <property name="show_sql">true</property>
       
        <!-- Drop and re-create the database schema on startup -->
        <property name="hbm2ddl.auto">update</property> 
        <!-- create / update -->
   
        <!-- Names the annotated entity class -->
        <mapping class="org.yash.dto.UserDetails"/>  
           
    </session-factory>


</hibernate-configuration>