Detail caching and level 2 caching in Java's Hibernate framework

  • 2020-04-01 04:35:03
  • OfStack

The cache

Today we will talk about entity state and hibernate caching in hibernate.
  1) first, let's take a look at the entity state:
  Entity state three main points: transient, persitent, detached.
  Look at the English should probably understand it.
  Transient: data is not yet corresponding to the data in the database.
  Persistent: is the data that corresponds to the data in the database, and any changes to it are reflected in the database.
  Detached: is index according to the corresponding with the data in the database, but because the session is closed, it changes will not affect the database record.
  Below we directly code to:


Transaction tx = session.beginTransaction(); 
User user = new User(); 
user.setName("shun"); 
//The user has not been saved to the database, and there is no corresponding record in the database table. It is transient
session.save(user); 
tx.commit(); 
//After committing, user becomes persistent
session.close(); 
//Shut down due to the session, at this time of the user for the detached state, it's all change is not reflected in the database.
     
Session session2 = sessionFactory.openSession(); 
tx = session2.beginTransaction(); 
user.setName("shun123"); 
session2.saveOrUpdate(user); 
tx.commit(); 
//When we call saveOrUpdate, user becomes persistent again, and all its changes are reflected in the database.
session2.close(); 

    We see the code. First, we define an object user. Before it is saved, it is transient state, and there is no corresponding record in the database. When we save and commit the changes, the user becomes a persistent state with a corresponding record in the database. And when we put the session is turned off, the user becomes detached, it changes will not be reflected in the database, unless we call manually saveOrUpdate corresponding updates and add methods, etc. But when we want to make it from persistent to transient state directly, what should we do? It is ok to delete directly, after the object is deleted, there is no corresponding record in the database, it will be transient state.
 
  Hibernate state transition is relatively simple, as transient state, no records corresponding to database and persistent and detached have corresponding record, but the only difference is detached are some of the state after the session closed. So what is the difference between transient and detached? There is no database table records corresponding to the problem.
 
  2) after looking at the state, let's take a look at hibernate's cache
  There are two types of hibernate cache, level 1 cache and level 2 cache.
  Level 1 cache: the so-called level 1 cache is the internal cache.
  Level 2 cache: this includes the application level cache, which in hibernate is called the SessionFactory cache, and the distributed cache, which is the safest way to cache.
  Look directly at the program:


public static void main(String[] args) { 
 
  Configuration cfg = new Configuration().configure(); 
  SessionFactory sessionFactory = cfg.buildSessionFactory(); 
  Session session = sessionFactory.openSession(); 
     
  User user = (User)session.load(User.class,new Long(29)); 
  System.out.println(user.getName()); 
     
  User user2 = (User)session.load(User.class,new Long(29)); 
  System.out.println(user2.getName()); 
     
  session.close(); 
} 

    The results:


Hibernate: select user0_.USER_ID as USER1_0_0_, user0_.USER_NAME as USER2_0_0_, user0_.age as age0_0_ from USER user0_ where user0_.USER_ID=? 
shun123123 
shun123123 

  In the example, we used load twice, but the result contained only one SQL statement, indicating that it was queried only once.
  Why? This is where hibernate's caching comes into play. After the first query, hibernate will find out the entity in the cache, the next check will first check the cache, to see if there is a corresponding ID of the entity exists, if there is direct extraction, otherwise the database query.
 
  Now let's change the code to:


User user = (User)session.load(User.class,new Long(29)); 
System.out.println(user.getName()); 
     
session.evict(user);//Delete the user from the cache
     
User user2 = (User)session.load(User.class,new Long(29)); 
System.out.println(user2.getName()); 
     
session.close(); 

    See the results:


Hibernate: select user0_.USER_ID as USER1_0_0_, user0_.USER_NAME as USER2_0_0_, user0_.age as age0_0_ from USER user0_ where user0_.USER_ID=? 
shun123123 
Hibernate: select user0_.USER_ID as USER1_0_0_, user0_.USER_NAME as USER2_0_0_, user0_.age as age0_0_ from USER user0_ where user0_.USER_ID=? 
shun123123 

    After we removed the user from the cache, the second query was pulled directly from the database.

Level 2 cache chat
First look at the entity class:


public class User implements Serializable{ 
 
  public Long id; 
  private String name; 
  private int age; 
   
} 

    I'm going to omit the mapping file, and you're going to write it.
  Take a look at the hibernate configuration file:


<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property> 
<property name="hibernate.cache.use_second_level_cache">true</property> 
<property name="hibernate.cache.use_query_cache">true</property> 

    We see that in provider_class we specified the ehcache provider class, so we also need ehcache.xml in the classpath:


<?xml version="1.0" encoding="UTF-8"?> 
<ehcache> 
  <diskStore path="java.io.path"/> 
  <defaultCache  
    maxElementsInMemory="10000" 
    eternal="false" 
    timeToIdleSeconds="120" 
    timeToLiveSeconds="120" 
    overflowToDisk="true" 
    /> 
</ehcache> 

  Next, let's look directly at the test method:


public static void main(String[] args) { 
 
  Configuration cfg = new Configuration().configure(); 
  SessionFactory sessionFactory = cfg.buildSessionFactory(); 
  Session session = sessionFactory.openSession(); 
 
  Query query = session.createQuery("from User user where name = 'shun123'"); 
  Iterator iter = query.iterate(); 
  while(iter.hasNext()) { 
    System.out.println(((User)iter.next()).getName()); 
  } 
   
  session.close(); 
   
  Session session2 = sessionFactory.openSession(); 
  Query query2 = session2.createQuery("from User user where name='shun123'"); 
  Iterator iter2 = query2.iterate(); 
  while(iter2.hasNext()) { 
    System.out.println(((User)iter2.next()).getName()); 
  } 
   
  session2.close(); 
 
} 

    After running, we can see:


Hibernate: select user0_.USER_ID as col_0_0_ from USER user0_ where user0_.USER_NAME='shun123' 
Hibernate: select user0_.USER_ID as USER1_0_0_, user0_.USER_NAME as USER2_0_0_, user0_.age as age0_0_ from USER user0_ where user0_.USER_ID=? 
shun123 
Hibernate: select user0_.USER_ID as col_0_0_ from USER user0_ where user0_.USER_NAME='shun123' 
shun123 

    We can see that it only performs a one-sentence search and does not fetch the ID to search on the second query, mainly due to the second-level cache.
 
  Let's first examine the code in the test method. In the test method, we opened two sessions respectively and created two queries respectively for the same Query. But two sessions can share the cache, which is the second level cache, the sessionfactory-level cache. As long as our Session is created by the same SessionFactory, we can share a secondary cache to reduce our interaction with the database.
  Let's take a look at the meaning of the configuration file:


<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property> 
<property name="hibernate.cache.use_second_level_cache">true</property> 
<property name="hibernate.cache.use_query_cache">true</property> 

    If we need to use level 2 caching, we first need to configure:


<property name="hibernate.cache.use_second_level_cache">true</property> 

    Do account opening level 2 cache, then pass:


<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property> 

    The class that specifies the second level cache is provided. In general, we use ehcache. The rest of my cache is not used and is not clear.
  As in our example, we only need to configure the two above to work perfectly, using the level 2 cache.
  So what is the third sentence for?


<property name="hibernate.cache.use_query_cache">true</property> 

    This configuration specifies that we need to use the cache when querying, and if we need to use this we need to call the query.setcacheable (true) method to enable it.
 
  Let's take a look at the code (we won't enable caching yet) :


public static void main(String[] args) { 
 
  Configuration cfg = new Configuration().configure(); 
  SessionFactory sessionFactory = cfg.buildSessionFactory(); 
  Session session = sessionFactory.openSession(); 
 
  Query query = session.createQuery("from User user where name = 'shun123'"); 
  List list = query.list(); 
  for (int i = 0; i < list.size(); i++){ 
    System.out.println(((User)list.get(i)).getName()); 
  } 
   
  session.close(); 
   
  Session session2 = sessionFactory.openSession(); 
  Query query2 = session2.createQuery("from User user where name='shun123'"); 
  List list2 = query2.list(); 
  for (int i = 0; i < list2.size(); i++){ 
    System.out.println(((User)list.get(i)).getName()); 
  } 
   
  session2.close(); 
 
} 

    The output here is:


Hibernate: select user0_.USER_ID as USER1_0_, user0_.USER_NAME as USER2_0_, user0_.age as age0_ from USER user0_ where user0_.USER_NAME='shun123' 
shun123 
Hibernate: select user0_.USER_ID as USER1_0_, user0_.USER_NAME as USER2_0_, user0_.age as age0_ from USER user0_ where user0_.USER_NAME='shun123' 
shun123 

    We can see that it doesn't make use of the cache, because we're using list here, and list is only written to the cache. So there's going to be two queries.
  So let's change that:


public static void main(String[] args) { 
 
  Configuration cfg = new Configuration().configure(); 
  SessionFactory sessionFactory = cfg.buildSessionFactory(); 
  Session session = sessionFactory.openSession(); 
 
  Query query = session.createQuery("from User user where name = 'shun123'"); 
  <span style="background-color: #ffffff;"><span style="color: #ff0000;">query.setCacheable(true);</span></span> 
  List list = query.list(); 
  for (int i = 0; i < list.size(); i++){ 
    System.out.println(((User)list.get(i)).getName()); 
  } 
   
  session.close(); 
   
  Session session2 = sessionFactory.openSession(); 
  Query query2 = session2.createQuery("from User user where name='shun123'"); 
  <span style="color: #ff0000;">query2.setCacheable(true);</span> 
  List list2 = query2.list(); 
  for (int i = 0; i < list2.size(); i++){ 
    System.out.println(((User)list.get(i)).getName()); 
  } 
   
  session2.close(); 
 
} 

    See the two lines of code in red. These are the two lines of code that we added to turn on the query cache. Now we see the result:


Hibernate: select user0_.USER_ID as USER1_0_, user0_.USER_NAME as USER2_0_, user0_.age as age0_ from USER user0_ where user0_.USER_NAME='shun123' 
shun123 
shun123 

    There's only one query left. Why? In those two lines of code red, we turn on the cache, remember, we need to use it twice. Make both queries cacheable to use the query cache.
  Criteria is a similar practice. In case some children forget how to write Criteria, I will put the code:


public static void main(String[] args) { 
 
  Configuration cfg = new Configuration().configure(); 
  SessionFactory sessionFactory = cfg.buildSessionFactory(); 
  Session session = sessionFactory.openSession(); 
 
  Criteria criteria1 = session.createCriteria(User.class); 
  criteria1.setCacheable(true); 
  criteria1.add(Restrictions.eq("name","shun123")); 
  List list = criteria1.list(); 
  for (int i = 0; i < list.size(); i++){ 
    System.out.println(((User)list.get(i)).getName()); 
  } 
   
  session.close(); 
   
  Session session2 = sessionFactory.openSession(); 
  Criteria criteria2 = session2.createCriteria(User.class); 
  criteria2.setCacheable(true); 
  criteria2.add(Restrictions.eq("name","shun123")); 
  List list2 = criteria2.list(); 
  for (int i = 0; i < list2.size(); i++){ 
    System.out.println(((User)list.get(i)).getName()); 
  } 
   
  session2.close(); 
 
} 

    Let's look at the results:


Hibernate: select this_.USER_ID as USER1_0_0_, this_.USER_NAME as USER2_0_0_, this_.age as age0_0_ from USER this_ where this_.USER_NAME=? 
shun123 
shun123 


Related articles: