Heim >Java >javaLernprogramm >Ausführliche Erläuterung des Cachings und des Second-Level-Cache im Java-Hibernate-Framework

Ausführliche Erläuterung des Cachings und des Second-Level-Cache im Java-Hibernate-Framework

高洛峰
高洛峰Original
2017-01-23 09:57:091303Durchsuche

Cache

Heute werden wir über den Entitätsstatus und den Ruhezustand-Cache im Ruhezustand sprechen.
1) Werfen wir zunächst einen Blick auf den Entitätsstatus:
Es gibt drei Haupttypen von Entitätsstatus: vorübergehend, dauerhaft und getrennt.
Sie sollten es wahrscheinlich verstehen, wenn Sie es auf Englisch lesen.
Vorübergehend: bedeutet, dass die Daten noch nicht mit den Daten in der Datenbank übereinstimmen.
Persistent: bedeutet, dass die Daten den Daten in der Datenbank entsprechen und alle Änderungen daran in der Datenbank widergespiegelt werden.
Getrennt: bedeutet, dass die Daten den Daten in der Datenbank entsprechen, aber da die Sitzung geschlossen ist, haben die vorgenommenen Änderungen keine Auswirkungen auf die Datensätze in der Datenbank.
Lassen Sie es uns direkt codieren:

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

Wenn wir den Code sehen, definieren wir zunächst einen Objektbenutzer. Bevor er gespeichert wird, befindet er sich im Übergangszustand und es gibt kein entsprechendes Objekt in der Datenbank. Aufzeichnen. Wenn wir die Änderung speichern und übermitteln, wird der Benutzer dauerhaft und verfügt über einen entsprechenden Datensatz in der Datenbank. Wenn wir die Sitzung schließen, wird der Benutzer getrennt und seine Änderungen werden nicht in der Datenbank widergespiegelt, es sei denn, wir rufen manuell saveOrUpdate und andere entsprechende Update- und Add-Methoden auf. Und was sollen wir tun, wenn wir direkt möchten, dass der Zustand von einem dauerhaften in einen vorübergehenden Zustand wechselt? Löschen Sie es einfach direkt. Nach dem Löschen verfügt das Objekt nicht über einen entsprechenden Datensatz in der Datenbank und wird in einen vorübergehenden Zustand versetzt.

Der Zustandsübergang von Hibernate ist relativ einfach. Wenn es sich im Übergangszustand befindet, gibt es keinen entsprechenden Datensatz in der Datenbank, während es entsprechende Datensätze für persistent und getrennt gibt, aber der einzige Unterschied besteht darin, dass nur getrennt verfügbar ist nachdem die Sitzung geschlossen wurde. Was ist also der Unterschied zwischen transient und distanziert? Es stellt sich die Frage, ob in der Datenbanktabelle ein entsprechender Datensatz vorhanden ist.

2) Nachdem wir den Status gelesen haben, werfen wir einen Blick auf den Cache von Hibernate.
Der Cache von Hibernate ist in zwei Typen unterteilt, den Cache der ersten Ebene und den Cache der zweiten Ebene.
First-Level-Cache: Der sogenannte First-Level-Cache ist gleichzeitig der interne Cache.
Cache der zweiten Ebene: Im Ruhezustand handelt es sich um den sogenannten SessionFactory-Cache. Dies ist die sicherste Cache-Methode.
Schauen wir uns das Programm direkt an:

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

Schauen Sie sich das Ergebnis an:

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

Im Beispiel haben wir Load zweimal verwendet, aber es gibt nur eine SQL-Anweisung im Ergebnis, das zeigt, dass es nur einmal überprüft wurde.
Warum? Hier kommt der Cache von Hibernate ins Spiel. Nachdem die erste Abfrage abgeschlossen ist, legt der Ruhezustand die erkannten Entitäten in den Cache. Bei der nächsten Abfrage wird zunächst überprüft, ob eine der ID entsprechende Entität vorhanden ist. Andernfalls wird die Datenbank abgefragt.

Als nächstes ändern wir den Code wie folgt:

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

Sehen Sie sich das Ergebnis an:

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

Nachdem wir den Benutzer aus dem Cache gelöscht haben, wird die zweite Abfrage ebenfalls direkt übernommen aus der Datenbank.

Level 2 Cache Small Talk
Sehen Sie sich zuerst die Entitätsklasse an:

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

Die Zuordnungsdatei wird weggelassen, jeder sollte in der Lage sein, sie zu schreiben.
Werfen wir einen Blick auf die Konfigurationsdatei für den Ruhezustand:

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

Wir sehen, dass wir die ehcache-Anbieterklasse in „provider_class“ angegeben haben, daher müssen wir auch ehcache.xml in den Klassenpfad einfügen:

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

Als nächstes schauen wir uns die Testmethode direkt an:

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


Nach dem Ausführen sehen wir:

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

Wir können sehen, dass nur ein Suchsatz durchgeführt und die ID für die zweite Abfrage nicht abgerufen wurde. Dies liegt hauptsächlich am Cache der zweiten Ebene.

Lassen Sie uns zunächst den Code in der Testmethode analysieren. In der Testmethode haben wir zwei Sitzungen geöffnet und zwei Abfragen erstellt, um dieselbe Abfrage auszuführen. Aber zwei Sitzungen können den Cache gemeinsam nutzen, nämlich den Cache der zweiten Ebene und den Cache der SessionFactory-Ebene. Solange unsere Sitzung von derselben SessionFactory erstellt wird, können wir den Cache der zweiten Ebene gemeinsam nutzen, um die Interaktion mit der Datenbank zu reduzieren.
Werfen wir einen Blick auf die Bedeutung der Konfigurationsdatei:

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

Wenn wir den Second-Level-Cache verwenden müssen, müssen wir zuerst Folgendes konfigurieren:

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

um den Cache der zweiten Ebene zu öffnen, und dann Pass:

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

Geben Sie die Anbieterklasse des Caches der zweiten Ebene an. Unter normalen Umständen verwenden wir alle ehcache Ich bin mir vorerst nicht sicher, weshalb ich vorerst nicht darüber sprechen werde.
Wie in unserem Beispiel gerade müssen wir nur die beiden oben genannten konfigurieren, und es kann normal ausgeführt werden und den Cache der zweiten Ebene verwenden.
Wozu dient also der dritte Satz?

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

Diese Konfiguration zeigt an, dass wir den Cache beim Abfragen verwenden müssen. Wenn wir dies verwenden müssen, müssen wir die Methode query.setCacheable(true) im Voraus aufrufen, um sie zu aktivieren.

Schauen wir uns gemeinsam den Code an (wir aktivieren das Caching nicht zuerst):

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

Das Ausgabeergebnis hier ist:

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

Wir sehen, dass es so ist Verwendet keinen Cache, da wir hier die Liste verwenden und die Liste nur in den Cache schreibt, aber nicht liest. Daher wird es hier zwei Abfragen geben.
Dann ändern wir es:

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中文网!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn