Home >Java >javaTutorial >Detailed explanation of caching and second-level cache in Java's Hibernate framework

Detailed explanation of caching and second-level cache in Java's Hibernate framework

高洛峰
高洛峰Original
2017-01-23 09:57:091304browse

Cache

Today we will talk about entity status and hibernate cache in hibernate.
1) First, let’s take a look at the entity status:
There are three main types of entity status: transient, persistent, and detached.
You should probably understand it if you read it in English.
Transient: means that the data has not yet corresponded to the data in the database.
Persistent: means that the data corresponds to the data in the database, and any changes to it will be reflected in the database.
Detached: means that the data corresponds to the data in the database, but because the session is closed, the modifications it makes will not affect the records in the database.
Let’s go directly to the code:

Transaction tx = session.beginTransaction(); 
User user = new User(); 
user.setName("shun"); 
//这里的user还未保存到数据库,数据库表中并没有与之对应的记录,它为transient状态 
session.save(user); 
tx.commit(); 
//提交之后user变为persistent状态 
session.close(); 
//由于session关闭,此时的user为detached状态,它的所有修改都不会反映到数据库中。 
      
Session session2 = sessionFactory.openSession(); 
tx = session2.beginTransaction(); 
user.setName("shun123"); 
session2.saveOrUpdate(user); 
tx.commit(); 
//当我们调用了saveOrUpdate之后,user重新变为persistent状态,它的所有修改都会反映到数据库中。 
session2.close();

When we see the code, first we define an object user. Before it is saved, it is in transient state and there is no corresponding record for it in the database. When we save and submit the modification, the user becomes persistent and has a corresponding record in the database. When we close the session, the user becomes detached, and its changes will not be reflected in the database unless we manually call saveOrUpdate and other corresponding update and add methods. And what should we do when we directly want it to change from persistent to transient state? Just delete it directly. After deletion, the object will have no corresponding record in the database, and it will become a transient state.

hibernate's state transition is relatively simple. When it is in the transient state, there is no corresponding record in the database, while there are corresponding records for persistent and detached, but the only difference is that detached is only available after the session is closed. status. So what is the difference between transient and detached? There is a question of whether there is a corresponding record in the database table.

2) After reading the status, let’s take a look at hibernate’s cache
Hibernate’s cache is divided into two types, the first-level cache and the second-level cache.
First-level cache: The so-called first-level cache is also the internal cache.
Second-level cache: It includes application-level cache. In hibernate, it is the so-called SessionFactory cache. The other is distributed cache. This is the safest cache method.
Let’s look at the program directly:

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(); 
}

Look at 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 there is only one SQL statement in the result, which shows that it was only queried once.
why? This is where hibernate's cache comes into play. After the first query is completed, hibernate will put the detected entities in the cache. When querying next time, it will first check the cache to see if there is an entity corresponding to the ID. If there is, it will be taken out directly. Otherwise, the database will be queried. .

Next we modify the code to:

User user = (User)session.load(User.class,new Long(29)); 
System.out.println(user.getName()); 
      
session.evict(user);//把user从缓存中删掉 
      
User user2 = (User)session.load(User.class,new Long(29)); 
System.out.println(user2.getName()); 
      
session.close();

See the result:

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 delete the user from the cache, the second query is also directly from the database Take it out.

Second Level Cache Talk
Let’s look at the entity class first:

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

The mapping file will be omitted, everyone should be able to write it.
Let’s 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 we have specified the ehcache provider class in provider_class, so we also need to put 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>

Connect Next, let’s take a look at the test method directly:

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 = &#39;shun123&#39;");
  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=&#39;shun123&#39;");
  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=&#39;shun123&#39;
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=&#39;shun123&#39;
shun123

We can see that it only executes a search, and In the second query, the ID was not retrieved for search, which is mainly due to the second-level cache.

Let’s first analyze the code in the test method. In the test method, we opened two Sessions and created two Queries to perform the same query. But two Sessions can share the cache, which is the second-level cache and SessionFactory-level cache. As long as our Session is created by the same SessionFactory, then we can share the second-level cache to reduce 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 the second-level cache, we first need to configure:

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

to open an account for the second-level cache, and then pass:

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

Specifies the provider class of the second-level cache. Under normal circumstances, we all use ehcache. I have not used the other ones for the time being, and I am not sure about them, so I won’t talk about them for the time being.
Like our example just now, we only need to configure the above two, and it can run normally and use the second level cache.
So what is the third sentence used for?

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

This configuration indicates that we need to use the cache when querying. If we need to use this, we must call the query.setCacheable(true) method in advance to enable it.

Let’s look at the code together (we don’t enable caching first):

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 = &#39;shun123&#39;");
  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=&#39;shun123&#39;");
  List list2 = query2.list();
  for (int i = 0; i < list2.size(); i++){
    System.out.println(((User)list.get(i)).getName());
  }
    
  session2.close();
  
}

The output result 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=&#39;shun123&#39;
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=&#39;shun123&#39;
shun123

We see that it does not use caching because We used a list here, and the list only writes to the cache but does not read. So there will be two queries here.
Then let’s modify it:

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 = &#39;shun123&#39;");
  <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=&#39;shun123&#39;");
  <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();
  
}

  看到红色的两句代码,这是我们进行添加的两个开启查询缓存的代码,现在我们看到结果:

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=&#39;shun123&#39;
shun123
shun123

  只剩一次查询了,为什么呢?就在那两句红色代码处,我们开启了缓存,记住,需要使用两次。把两个query都设成可缓存的才能使用查询缓存。
 Criteria也是类似的做法,为免有些童鞋忘记了Criteria怎么写了,我还是放一下代码:

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();
  
}

  我们看结果:

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

更多详解Java的Hibernate框架中的缓存与二级缓存相关文章请关注PHP中文网!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn