Hibernate cache detail

  • 2020-06-03 06:27:36
  • OfStack

1. What is caching?

The database cache refers to the data between the application and the physical data source. Copy the data from the physical data source to the cache. Caching improves efficiency by reducing the frequency with which applications access physical data sources. The medium for caching is usually memory or hard disk.

There are three types of Hibernate caching: level 1 cache, level 2 cache, and query cache.

2. Level 1 cache

The level 1 cache, the Session cache, is automatically managed by Session without program intervention. The level 1 cache is loaded and cached based on the object's ID. The following code:


@Override
  public void testCache() {
    // TODO Auto-generated method stub
    Session session = sessionFactory.openSession();
    Transaction tx = session.beginTransaction(); 
    Course c = (Course) session.get(Course.class, 1);
    System.out.println("Name:" + c.getName());
    c = (Course) session.get(Course.class, 1);
    System.out.println("Name:" + c.getName());
    tx.commit();
    session.close();
  }

Operation results:


Hibernate: 
  select
    course0_.ID as ID0_0_,
    course0_.NAME as NAME0_0_,
    course0_.COMMENT as COMMENT0_0_ 
  from
    clas course0_ 
  where
    course0_.ID=?
Name: Principle of computer 
Name: Principle of computer 

In the first query, the SQL statement was generated, and the object was placed in the level 1 cache. In the second query, the object was directly found in the level 1 cache, so there was no need to generate the SQL statement again.

Here's another example:


@Override
  public void testCache() {
    // TODO Auto-generated method stub
    Session session = sessionFactory.openSession();
    Transaction tx = session.beginTransaction(); 
    Course c = (Course) session.get(Course.class, 1);
    System.out.println("Name:" + c.getName());
    tx.commit();
    session.close();
    session = sessionFactory.openSession();
    tx = session.beginTransaction(); 
    c = (Course) session.get(Course.class, 1);
    System.out.println("Name:" + c.getName());
    tx.commit();
    session.close();
  }

Since the level 1 cache is an Session level cache, after Session is closed, the level 1 cache will no longer exist and the second query will generate SQL statements:


Hibernate: 
  select
    course0_.ID as ID0_0_,
    course0_.NAME as NAME0_0_,
    course0_.COMMENT as COMMENT0_0_ 
  from
    clas course0_ 
  where
    course0_.ID=?
Name: Principle of computer 
Hibernate: 
  select
    course0_.ID as ID0_0_,
    course0_.NAME as NAME0_0_,
    course0_.COMMENT as COMMENT0_0_ 
  from
    clas course0_ 
  where
    course0_.ID=?
Name: Principle of computer 

3. Level 2 cache

A level 2 cache, known as SessionFactory cache, is similar to a level 1 cache in that it is loaded and cached according to the object's ID. The difference is that a level 1 cache is only valid within Session and a level 2 cache is valid within SessionFactory. When accessing an ID object, go to level 1 cache and if not, go to level 2 cache. Level 2 cache includes EHCache, OSCache, SwarmCache and JBossCache. Take EHCache as an example.

Level 2 cache requires program management. First, configure Maven to download the associated Jar and add:


<dependency> 
      <groupId>org.hibernate</groupId> 
      <artifactId>hibernate-ehcache</artifactId> 
      <version>4.1.0.Final</version> 
    </dependency>
    <dependency> 
      <groupId>net.sf.ehcache</groupId> 
      <artifactId>ehcache</artifactId> 
      <version>2.8.3</version> 
    </dependency>

Create EHCache profile ehcache.xml:


<ehcache>
  <diskStore path="E:\Eclipse\MyWorkspace\Cache"/>
  <defaultCache
    maxElementsInMemory="10000"
    eternal="true"
    timeToIdleSeconds="120"
    timeToLiveSeconds="120"
    overflowToDisk="true"
  />
  <cache name="com.hzhi.course.entity.Course"
    maxElementsInMemory="10000"
    eternal="true"
    timeToIdleSeconds="300"
    timeToLiveSeconds="600"
    overflowToDisk="true"
  />
</ehcache>

defaultCache is the default setting, and the following cache indicates which class to cache at level 2. It sets the maximum number of cached objects, whether they are permanent, the maximum number of free seconds, the maximum number of live seconds, whether they are written to disk when memory is full, the path to write to disk, and so on.

Modify the hbm file for the class that needs to be cached:


 <class name="com.hzhi.course.entity.Course" table="clas">
    <cache usage="read-only"/>
        ......
  </class>

usage has set the concurrent access policy, generally set to ES67en-ES68en.

Modify the configuration of SessionFactory in ES71en.xml to add 1 of the attributes of level 2 cache:


<!-- SessionFactory -->
   <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" >
      <ref local="dataSource"/>
    </property>
    <!--  configuration Hibernate The properties of the  -->
    <property name="hibernateProperties">
      <props>
        <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
        <prop key="hibernate.show_sql">true</prop>
        <prop key="hibernate.format_sql">true</prop>
        <prop key="hibernate.connection.isolation">8</prop>
        <!-- 2 Level cache  -->
        <prop key="hibernate.cache.use_second_level_cache">false</prop>
        <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>        
        <prop key="hibernate.cache.provider_configuration_file_resource_path">WEB-INF/ehcache.xml</prop>        
      </props>
    </property>
     ......
   </bean>

Run the following example:


@Override
  public void testCache() {
    // TODO Auto-generated method stub
    Session session = sessionFactory.openSession();
    Transaction tx = session.beginTransaction(); 
    Course c = (Course) session.get(Course.class, 1);
    System.out.println("Name:" + c.getName());
    tx.commit();
    session.close();
    session = sessionFactory.openSession();
    tx = session.beginTransaction(); 
    c = (Course) session.get(Course.class, 1);
    System.out.println("Name:" + c.getName());
    tx.commit();
    session.close();
  }

Results:


Hibernate: 
  select
    course0_.ID as ID0_0_,
    course0_.NAME as NAME0_0_,
    course0_.COMMENT as COMMENT0_0_ 
  from
    clas course0_ 
  where
    course0_.ID=?
Name: Principle of computer 
Name: Principle of computer 

Although Session was turned off, the level 2 cache still exists, so only one SQL statement was generated.

Here are some examples:


Hibernate: 
  select
    course0_.ID as ID0_0_,
    course0_.NAME as NAME0_0_,
    course0_.COMMENT as COMMENT0_0_ 
  from
    clas course0_ 
  where
    course0_.ID=?
Name: Principle of computer 
Name: Principle of computer 
0

Results:


Hibernate: 
  select
    course0_.ID as ID0_0_,
    course0_.NAME as NAME0_0_,
    course0_.COMMENT as COMMENT0_0_ 
  from
    clas course0_ 
  where
    course0_.ID=?
Name: Principle of computer 
Name: Principle of computer 
1

When using Query's list() method, the SQL statement is generated once to query all objects. When using the iterate() method, the ID statement of all objects is generated first, and then the SQL statement query is generated once per ID. The iterate() method is also used in the second Session. First, SQL statements are generated once to obtain ID. Then, objects are found according to ID.

Both level 1 and level 2 caches can cache only objects, not property values. Here are some examples:


Hibernate: 
  select
    course0_.ID as ID0_0_,
    course0_.NAME as NAME0_0_,
    course0_.COMMENT as COMMENT0_0_ 
  from
    clas course0_ 
  where
    course0_.ID=?
Name: Principle of computer 
Name: Principle of computer 
2

Operation results:


Hibernate: 
  select
    course0_.NAME as col_0_0_ 
  from
    clas course0_
 Principle of computer 
 Computer network 
 Database principle 
C language 
 The university English A
Java
Linux
 Higher mathematics 
 Chinese language and literature 
 University physics 
 Software engineering 
----------
Hibernate: 
  select
    course0_.NAME as col_0_0_ 
  from
    clas course0_
 Principle of computer 
 Computer network 
 Database principle 
C language 
 The university English A
Java
Linux
 Higher mathematics 
 Chinese language and literature 
 University physics 
 Software engineering 
----------

Although level 2 caching is enabled, the result of the query is not an object but an attribute, so there is no caching. The second query still generates a query statement. To solve this problem, query caching is required.

3. Query cache

Based on the configuration of level 2 cache, query cache can be set. Add 1 line to SessionFactory:

<prop key="hibernate.cache.use_query_cache">true</prop>

The query cache is turned on. The query cache is also an SessionFactory level cache and is valid throughout SessionFactory.

Turn off the level 2 cache, run the following example, and add setCacheable(true) after Query to open the query cache:


Hibernate: 
  select
    course0_.ID as ID0_0_,
    course0_.NAME as NAME0_0_,
    course0_.COMMENT as COMMENT0_0_ 
  from
    clas course0_ 
  where
    course0_.ID=?
Name: Principle of computer 
Name: Principle of computer 
4

Results:


Hibernate: 
  select
    course0_.ID as ID0_0_,
    course0_.NAME as NAME0_0_,
    course0_.COMMENT as COMMENT0_0_ 
  from
    clas course0_ 
  where
    course0_.ID=?
Name: Principle of computer 
Name: Principle of computer 
5

Since the HQL statement for the two queries is 1, only one SQL statement is generated. But if the second query is changed to 1:


Hibernate: 
  select
    course0_.ID as ID0_0_,
    course0_.NAME as NAME0_0_,
    course0_.COMMENT as COMMENT0_0_ 
  from
    clas course0_ 
  where
    course0_.ID=?
Name: Principle of computer 
Name: Principle of computer 
6

Results:


Hibernate: 
  select
    course0_.ID as ID0_0_,
    course0_.NAME as NAME0_0_,
    course0_.COMMENT as COMMENT0_0_ 
  from
    clas course0_ 
  where
    course0_.ID=?
Name: Principle of computer 
Name: Principle of computer 
7

Since the HQL statement has changed, the second SQL statement is also generated.

The query cache can cache properties as well as objects, but when caching objects, only ID of the object is cached, not the entire object. Here are some examples:


@Override
  public void testCache() {
    // TODO Auto-generated method stub
    Session session = sessionFactory.openSession();
    Transaction tx = session.beginTransaction(); 
    Query query = session.createQuery("from Course");
    query.setCacheable(true);
    List<Course> list = query.list();
    for (int i=0; i<list.size(); i++){
      System.out.println(list.get(i).getName()); 
    }
    System.out.println("----------"); 
    tx.commit();
    session.close();
    session = sessionFactory.openSession();
    tx = session.beginTransaction();    
    query = session.createQuery("from Course"); 
    query.setCacheable(true);
    list = query.list();
    for (int i=0; i<list.size(); i++){
      System.out.println(list.get(i).getName()); 
    }
    System.out.println("----------");
    tx.commit();
    session.close();
  }

Results:


Hibernate: 
  select
    course0_.ID as ID0_0_,
    course0_.NAME as NAME0_0_,
    course0_.COMMENT as COMMENT0_0_ 
  from
    clas course0_ 
  where
    course0_.ID=?
Name: Principle of computer 
Name: Principle of computer 
9

Because the query cache is turned on, the level 2 cache is not turned on. Although the list() method is used to query all the objects once, the query cache only caches the object ID, not the whole object. Therefore, in the second Session, the HQL, "from Course", does not generate SQL statements because it is the same as the previous one. However, there is no level 2 cache and the whole object is not cached, so the SQL statements can only be generated once per ID. Although the list() method is used both times, the first time is to generate the SQL statement to query all the objects once, and the second time is to generate the SQL statement based on the ID1 in the query cache.

If both query cache and level 2 cache are turned on, there is no need to generate SQL statements according to ID in the second Session:


Hibernate: 
  select
    course0_.ID as ID0_,
    course0_.NAME as NAME0_,
    course0_.COMMENT as COMMENT0_ 
  from
    clas course0_
 Principle of computer 
 Computer network 
 Database principle 
C language 
 The university English A
Java
Linux
 Higher mathematics 
 Chinese language and literature 
 University physics 
 Software engineering 
----------
 Principle of computer 
 Computer network 
 Database principle 
C language 
 The university English A
Java
Linux
 Higher mathematics 
 Chinese language and literature 
 University physics 
 Software engineering 
----------

Related articles: