Monday, June 17, 2013

32 - Caching-in-Hibernate

In this tutorial, we'll learn about Hibernate's cache support: both first level (Session) and second level cache.

Good tutorials
Hibernate uses two different caches for objects: first-level cache and second-level cache.
1.1) 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.

1.2) Second-level cache :
Second-level cache always associates with the Session Factory object. While running the transactions, in between it loads the objects at the Session Factory level, so that those objects will available to the entire application, don’t bounds to single user. Since the objects are already loaded in the cache, whenever an object is returned by the query, at that time no need to go for a database transaction. In this way the second level cache works. Here we can use query level cache also. Later we will discuss about it.

2) Cache Implementations
Hibernate supports four open-source cache implementations named
1.       EHCache (Easy Hibernate Cache)
2.       OSCache (Open Symphony Cache)
3.       Swarm Cache, and
4.       JBoss Tree Cache.
Each cache has different performance, memory use, and configuration possibilities.

First level cache - Session
Second level Cache
                - Across sessions in an application
                - Across applications
                - Across clusters


If you call below statements only one call goes to DB
UserDetails user=(UserDetails)session.get(UserDetails.class, 1);
UserDetails user2=(UserDetails)session.get(UserDetails.class, 1);

/**********************************************/
Session session = sessionFactory.openSession();
session.beginTransaction();
UserDetails user=(UserDetails)session.get(UserDetails.class, 1);
session.getTransaction().commit();
session.close();
                                                               
Session session2 = sessionFactory.openSession();
session2.beginTransaction();
UserDetails user2=(UserDetails)session2.get(UserDetails.class, 11);
session2.getTransaction().commit();
session2.close();

If we run above code it will two select queries because if session close than cache also close. In this scenario we require second level cache so that second query should come from cache, if record doent match then hit the query to database.
/**********************************************/

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.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;

@Entity
@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>

        <!-- 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>

1 comment:

  1. Happy to found this blog. Good Post!. It was so good to read and useful to improve my knowledge as updated one, keep blogging. Hibernate Training in Electronic City
    Java Training in Electronic City

    ReplyDelete