Maison  >  Article  >  Java  >  Explication détaillée de la mise en cache et du cache de deuxième niveau dans le framework Hibernate de Java

Explication détaillée de la mise en cache et du cache de deuxième niveau dans le framework Hibernate de Java

高洛峰
高洛峰original
2017-01-23 09:57:091294parcourir

Mise en cache

Aujourd'hui, nous parlerons du statut de l'entité et du cache d'hibernation en veille prolongée.
1) Tout d'abord, examinons le statut de l'entité :
Il existe trois principaux types de statut d'entité : transitoire, persistant et détaché.
Vous devriez probablement le comprendre si vous le lisez en anglais.
Transitoire : signifie que les données ne correspondent pas encore aux données de la base de données.
Persistant : signifie que les données correspondent aux données de la base de données et que toute modification apportée à celles-ci sera reflétée dans la base de données.
Détaché : signifie que les données correspondent aux données de la base de données, mais comme la session est fermée, les modifications qu'elle apporte n'affecteront pas les enregistrements de la base de données.
Codons-le directement :

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

Lorsque nous voyons le code, nous définissons d'abord un utilisateur d'objet Avant qu'il ne soit enregistré, il est dans un état transitoire et il n'y a pas d'objet correspondant dans la base de données. Enregistrer. Lorsque nous enregistrons et soumettons la modification, l'utilisateur devient persistant et dispose d'un enregistrement correspondant dans la base de données. Lorsque nous fermons la session, l'utilisateur devient détaché et ses modifications ne seront pas reflétées dans la base de données à moins que nous appelions manuellement saveOrUpdate et d'autres méthodes de mise à jour et d'ajout correspondantes. Et que devons-nous faire lorsque nous souhaitons directement qu’il passe d’un état persistant à un état transitoire ? Supprimez-le simplement directement. Après la suppression, l'objet n'aura aucun enregistrement correspondant dans la base de données et deviendra un état transitoire.

La transition d'état d'Hibernate est relativement simple Lorsqu'il est dans l'état transitoire, il n'y a pas d'enregistrement correspondant dans la base de données, alors qu'il existe des enregistrements correspondants pour persistant et détaché, mais la seule différence est que détaché n'est disponible que. après la fermeture de la session. Alors, quelle est la différence entre transitoire et détaché ? La question se pose de savoir s'il existe un enregistrement correspondant dans la table de la base de données.

2) Après avoir lu le statut, jetons un œil au cache d'Hibernate
Le cache d'Hibernate est divisé en deux types, le cache de premier niveau et le cache de deuxième niveau.
Cache de premier niveau : Le cache dit de premier niveau est également le cache interne.
Cache de deuxième niveau : il inclut le cache au niveau de l'application. En veille prolongée, il s'agit du cache dit SessionFactory. L'autre est le cache distribué. Il s'agit de la méthode de cache la plus sûre.
Regardons directement le programme :

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

Regardez le résultat :

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

Dans l'exemple, nous avons utilisé load deux fois, mais il n'y a qu'une seule instruction SQL dans le résultat, ce qui montre qu'il n'a été vérifié qu'une seule fois.
Pourquoi ? C'est là que le cache d'hibernate entre en jeu. Une fois la première requête terminée, hibernate mettra les entités détectées dans le cache. Lors de la prochaine requête, il vérifiera d'abord le cache pour voir s'il existe une entité correspondant à l'ID. S'il y en a, elle sera directement supprimée. . Sinon, la base de données sera interrogée.

Ensuite, nous modifions le code pour :

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

Voir le résultat :

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

Après avoir supprimé l'utilisateur du cache, la deuxième requête est également prise directement à partir de la base de données.

Cache niveau 2 Small Talk
Regardez d'abord la classe d'entité :

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

Le fichier de mappage est omis, tout le monde devrait pouvoir l'écrire.
Jetons un coup d'œil au fichier de configuration d'hibernate :

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

Nous voyons que nous avons spécifié la classe du fournisseur ehcache dans supplier_class, nous devons donc également mettre ehcache.xml dans le chemin de classe :

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

Ensuite, examinons directement la méthode de test :

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


Après l'avoir exécutée, nous pouvons voir :

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

Nous pouvons voir qu'il n'a effectué qu'une seule phrase de recherche et n'a pas récupéré l'ID pour la deuxième requête. Cela est principalement dû au cache de deuxième niveau.

Analysons d'abord le code dans la méthode de test. Dans la méthode de test, nous avons ouvert deux sessions et créé deux requêtes pour effectuer la même requête. Mais deux sessions peuvent partager le cache, qui est le cache de deuxième niveau et le cache de niveau SessionFactory. Tant que notre session est créée par la même SessionFactory, nous pouvons alors partager le cache de deuxième niveau pour réduire l'interaction avec la base de données.
Voyons la signification du fichier de configuration :

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

Si nous devons utiliser le cache de deuxième niveau, nous devons d'abord configurer :

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

pour ouvrir le cache de deuxième niveau, puis Pass :

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

Spécifiez la classe du fournisseur du cache de deuxième niveau. Dans des circonstances normales, nous utilisons tous ehcache, je n'ai pas utilisé les autres pour le. pour le moment, et je n'en suis pas sûr, donc je n'en parlerai pas pour le moment.
Comme notre exemple tout à l'heure, il nous suffit de configurer les deux ci-dessus, et il peut fonctionner normalement et utiliser le cache de deuxième niveau.
Alors à quoi sert la troisième phrase ?

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

Cette configuration indique que nous devons utiliser le cache lors de l'interrogation. Si nous devons l'utiliser, nous devons appeler la méthode query.setCacheable(true) à l'avance pour l'activer.

Regardons le code ensemble (nous n'activons pas la mise en cache en premier) :

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

Le résultat de sortie ici est :

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

Nous voyons qu'il n'utilise pas le cache, car nous utilisons list ici, et list écrit uniquement dans le cache mais ne lit pas. Il y aura donc deux requêtes ici.
Alors modifions-le :

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

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn