Maison  >  Article  >  Java  >  Explication détaillée de la mise en cache et de l'utilisation d'instructions SQL natives dans le framework Hibernate de Java

Explication détaillée de la mise en cache et de l'utilisation d'instructions SQL natives dans le framework Hibernate de Java

高洛峰
高洛峰original
2017-01-23 11:48:481079parcourir

Hibernate Cache
La mise en cache concerne l'optimisation des performances des applications et se situe entre l'application et la base de données pour éviter plusieurs accès à la base de données et permettre aux applications critiques en termes de performances de mieux fonctionner.

La mise en cache est très importante pour Hibernate, qui utilise un schéma de mise en cache à plusieurs niveaux comme décrit ci-dessous :

Explication détaillée de la mise en cache et de lutilisation dinstructions SQL natives dans le framework Hibernate de Java

Cache de premier niveau :
Cache de premier niveau Il s'agit du cache de session et c'est un cache obligatoire par lequel toutes les requêtes doivent passer. L'objet Session conserve son propre pouvoir en tant qu'objet, avant d'être soumis à la base de données.

Si plusieurs mises à jour sont émises pour un objet, Hibernate tente de retarder les mises à jour aussi longtemps que possible afin de réduire le nombre d'instructions SQL de mise à jour émises. Si vous fermez la session, tous les objets mis en cache seront perdus, soit conservés, soit mis à jour dans la base de données.

Cache L2 :
Le cache L2 est un cache optionnel et le cache L1 sera toujours consulté avant toute tentative de recherche d'un objet dans le cache L2. Le cache de deuxième niveau peut être configuré par classe et par collection et est responsable de la mise en cache des objets au sein de la session.

Tout cache tiers peut utiliser Hibernate. L'interface org.hibernate.cache.CacheProvider fournit une implémentation de cache de handles qui doit être implémentée pour fournir Hibernate.

Cache au niveau des requêtes :
Hibernate implémente également l'intégration étroite du cache de jeu de résultats de requête et du cache secondaire.

Il s'agit d'une fonctionnalité facultative qui nécessite deux caches physiques supplémentaires pour contenir les résultats des requêtes mis en cache et l'horodatage de la dernière mise à jour d'une table. Ceci n'est utile que pour les requêtes exécutées fréquemment en utilisant les mêmes paramètres.

Cache niveau 2 :
Hibernate utilise le cache de premier niveau, par défaut vous ne faites rien pour utiliser le cache de premier niveau. Passons directement au cache facultatif de deuxième niveau. Toutes les classes ne bénéficient pas de la mise en cache, il est donc important de pouvoir désactiver le cache de deuxième niveau

Le cache de deuxième niveau Hibernate est configuré en deux étapes. Tout d’abord, vous devez décider de la stratégie de concurrence à utiliser. Après cela, vous pouvez configurer l'expiration du cache et utiliser les propriétés du cache physique de provisionnement du cache.

Stratégie de concurrence :
Une stratégie de concurrence est un intermédiaire chargé de stocker les éléments de données dans le cache et de les récupérer du cache. Si vous souhaitez activer la mise en cache de deuxième niveau, vous devrez décider, pour chaque classe de persistance et collection, la stratégie de concurrence de cache à utiliser.

Transactionnel : utilisez cette stratégie où les principales données lues visent à empêcher les transactions simultanées de données obsolètes, ce qui est critique dans les rares cas de mises à jour.

Lecture-écriture : utilisez à nouveau cette stratégie pour lire principalement les données là où il est essentiel d'empêcher les transactions simultanées à partir de données obsolètes dans les rares cas de mise à jour.

Nonstrict-read-write : Cette stratégie ne garantit pas la cohérence entre le cache et la base de données. L’utilisation de cette stratégie n’est pas critique si les données changent rarement et que la probabilité de données obsolètes est faible.

Lecture seule : la stratégie de concurrence s'applique aux données et ne change jamais. Les données d'utilisation sont uniquement à titre de référence.

Si nous envisageons d'utiliser la mise en cache de deuxième niveau pour notre classe Employee, ajoutons les éléments de mappage requis pour indiquer à Hibernate d'utiliser une stratégie de mise en cache en lecture-écriture pour les instances Employee.

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
 "-//Hibernate/Hibernate Mapping DTD//EN"
 "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 
 
<hibernate-mapping>
  <class name="Employee" table="EMPLOYEE">
   <meta attribute="class-description">
     This class contains the employee detail. 
   </meta>
   <cache usage="read-write"/>
   <id name="id" type="int" column="id">
     <generator class="native"/>
   </id>
   <property name="firstName" column="first_name" type="string"/>
   <property name="lastName" column="last_name" type="string"/>
   <property name="salary" column="salary" type="int"/>
  </class>
</hibernate-mapping>

L'attribut usage="read-write" indique à Hibernate d'utiliser un cache défini par une stratégie de concurrence lecture-écriture.

Fournisseur de cache :
Après avoir examiné la stratégie de concurrence qui utilisera vos classes candidates au cache, l'étape suivante consiste à choisir un fournisseur de cache. Hibernate force le choix d'un cache pour servir l'ensemble de l'application.

Explication détaillée de la mise en cache et de lutilisation dinstructions SQL natives dans le framework Hibernate de Java

Cache fourni dans le fichier de configuration hibernate.cfg.xml spécifié. Sélectionnez EHCache comme fournisseur de cache de deuxième niveau :

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM 
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
 
<hibernate-configuration>
  <session-factory>
  <property name="hibernate.dialect">
   org.hibernate.dialect.MySQLDialect
  </property>
  <property name="hibernate.connection.driver_class">
   com.mysql.jdbc.Driver
  </property>
 
  <!-- Assume students is the database name -->
  <property name="hibernate.connection.url">
   jdbc:mysql://localhost/test
  </property>
  <property name="hibernate.connection.username">
   root
  </property>
  <property name="hibernate.connection.password">
   root123
  </property>
  <property name="hibernate.cache.provider_class">
   org.hibernate.cache.EhCacheProvider
  </property>
 
  <!-- List of XML mapping files -->
  <mapping resource="Employee.hbm.xml"/>
 
</session-factory>
</hibernate-configuration>

Maintenant, vous devez spécifier les propriétés de la zone de cache. EHCache possède son propre fichier de configuration ehcache.xml, qui se trouve dans le CLASSPATH de l'application. La configuration du cache de la classe Employee dans ehcache.xml pourrait ressembler à ceci :

<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
 
<cache name="Employee"
maxElementsInMemory="500"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false"
/>

Ça y est, activez maintenant le cache de deuxième niveau de la classe Employee et Hibernate dispose désormais du cache de deuxième niveau, chaque fois qu'un employé est parcouru ou Lors du chargement des employés par identifiant.

devrait analyser toutes vos classes et choisir la stratégie de mise en cache appropriée pour chaque classe. Parfois, le cache de deuxième niveau peut dégrader les performances de l'application. Il est donc recommandé de tester l'application pour la première fois sans activer la mise en cache, ce qui est parfait pour la mise en cache et la vérification des performances. Si la mise en cache n’améliore pas les performances du système, il ne sert à rien de rendre disponible un quelconque type de cache.

Cache au niveau des requêtes :
Pour utiliser le cache de requêtes, vous devez d'abord l'activer dans le fichier de configuration à l'aide de la propriété hibernate.cache.use_query_cache="true". Si vous définissez cette propriété sur true, laissez Hibernate créer le cache requis en mémoire pour contenir les requêtes et les jeux d'identifiants.

Ensuite, pour utiliser le cache de requêtes, vous pouvez utiliser la méthode setCacheable(Boolean) de la classe Query. Par exemple :

Session session = SessionFactory.openSession();
Query query = session.createQuery("FROM EMPLOYEE");
query.setCacheable(true);
List users = query.list();
SessionFactory.closeSession();

Hibernate也支持通过一个缓存区域的概念非常细粒度的缓存支持。缓存区是这是给定一个名称缓存的一部分。

Session session = SessionFactory.openSession();
Query query = session.createQuery("FROM EMPLOYEE");
query.setCacheable(true);
query.setCacheRegion("employee");
List users = query.list();
SessionFactory.closeSession();

此代码使用方法告诉Hibernate来存储和查找在缓存中的员工方面的查询。


Hibernate原生SQL
可以使用原生SQL来表达数据库查询,如果想利用数据库特有的功能,如查询提示或者Oracle中的CONNECT关键字。 Hibernate3.x允许使用手写SQL语句,包括存储过程,所有的创建,更新,删除和load操作。

应用程序将从会话创建一个原生SQL查询(Session接口上)createSQLQuery()方法:

public SQLQuery createSQLQuery(String sqlString) throws HibernateException
当传递一个包含SQL查询到createSQLQuery()方法,可以将SQL结果与任何现有的Hibernate实体,联接,或者一个标量结果使用addEntity()方法,addJoin(),和addScalar()方法关联的字符串。

标量查询:
最基本的SQL查询是从一个或多个表中得到标量(数值)的列表。以下是语法使用原生SQL标量的值:

String sql = "SELECT first_name, salary FROM EMPLOYEE";
SQLQuery query = session.createSQLQuery(sql);
query.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
List results = query.list();

实体的查询:
上面的查询都是返回标量值,也就是从resultset中返回的“裸”数据。以下是语法通过addEntity()方法来从原生SQL查询获得实体对象作为一个整体。

String sql = "SELECT * FROM EMPLOYEE";
SQLQuery query = session.createSQLQuery(sql);
query.addEntity(Employee.class);
List results = query.list();

命名SQL查询:
以下是语法通过addEntity()方法来从原生SQL查询获得实体对象和使用命名SQL查询。

String sql = "SELECT * FROM EMPLOYEE WHERE id = :employee_id";
SQLQuery query = session.createSQLQuery(sql);
query.addEntity(Employee.class);
query.setParameter("employee_id", 10);
List results = query.list();

Native SQL 例子:
考虑下面的POJO类:

public class Employee {
  private int id;
  private String firstName;
  private String lastName; 
  private int salary;
 
  public Employee() {}
  public Employee(String fname, String lname, int salary) {
   this.firstName = fname;
   this.lastName = lname;
   this.salary = salary;
  }
  public int getId() {
   return id;
  }
  public void setId( int id ) {
   this.id = id;
  }
  public String getFirstName() {
   return firstName;
  }
  public void setFirstName( String first_name ) {
   this.firstName = first_name;
  }
  public String getLastName() {
   return lastName;
  }
  public void setLastName( String last_name ) {
   this.lastName = last_name;
  }
  public int getSalary() {
   return salary;
  }
  public void setSalary( int salary ) {
   this.salary = salary;
  }
}

让我们创建下面的EMPLOYEE表来存储Employee对象:

create table EMPLOYEE (
  id INT NOT NULL auto_increment,
  first_name VARCHAR(20) default NULL,
  last_name VARCHAR(20) default NULL,
  salary   INT default NULL,
  PRIMARY KEY (id)
);

以下将被映射文件。

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
 "-//Hibernate/Hibernate Mapping DTD//EN"
 "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
 
<hibernate-mapping>
  <class name="Employee" table="EMPLOYEE">
   <meta attribute="class-description">
     This class contains the employee detail.
   </meta>
   <id name="id" type="int" column="id">
     <generator class="native"/>
   </id>
   <property name="firstName" column="first_name" type="string"/>
   <property name="lastName" column="last_name" type="string"/>
   <property name="salary" column="salary" type="int"/>
  </class>
</hibernate-mapping>

   

最后,我们将创建应用程序类的main()方法来运行,我们将使用原生SQL查询的应用程序:

import java.util.*;
  
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.SQLQuery;
import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.cfg.Configuration;
 
public class ManageEmployee {
  private static SessionFactory factory;
  public static void main(String[] args) {
   try{
     factory = new Configuration().configure().buildSessionFactory();
   }catch (Throwable ex) {
     System.err.println("Failed to create sessionFactory object." + ex);
     throw new ExceptionInInitializerError(ex);
   }
   ManageEmployee ME = new ManageEmployee();
 
   /* Add few employee records in database */
   Integer empID1 = ME.addEmployee("Zara", "Ali", 2000);
   Integer empID2 = ME.addEmployee("Daisy", "Das", 5000);
   Integer empID3 = ME.addEmployee("John", "Paul", 5000);
   Integer empID4 = ME.addEmployee("Mohd", "Yasee", 3000);
 
   /* List down employees and their salary using Scalar Query */
   ME.listEmployeesScalar();
 
   /* List down complete employees information using Entity Query */
   ME.listEmployeesEntity();
  }
  /* Method to CREATE an employee in the database */
  public Integer addEmployee(String fname, String lname, int salary){
   Session session = factory.openSession();
   Transaction tx = null;
   Integer employeeID = null;
   try{
     tx = session.beginTransaction();
     Employee employee = new Employee(fname, lname, salary);
     employeeID = (Integer) session.save(employee);
     tx.commit();
   }catch (HibernateException e) {
     if (tx!=null) tx.rollback();
     e.printStackTrace();
   }finally {
     session.close();
   }
   return employeeID;
  }
 
  /* Method to READ all the employees using Scalar Query */
  public void listEmployeesScalar( ){
   Session session = factory.openSession();
   Transaction tx = null;
   try{
     tx = session.beginTransaction();
     String sql = "SELECT first_name, salary FROM EMPLOYEE";
     SQLQuery query = session.createSQLQuery(sql);
     query.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
     List data = query.list();
 
     for(Object object : data)
     {
      Map row = (Map)object;
      System.out.print("First Name: " + row.get("first_name"));
      System.out.println(", Salary: " + row.get("salary"));
     }
     tx.commit();
   }catch (HibernateException e) {
     if (tx!=null) tx.rollback();
     e.printStackTrace();
   }finally {
     session.close();
   }
  }
 
  /* Method to READ all the employees using Entity Query */
  public void listEmployeesEntity( ){
   Session session = factory.openSession();
   Transaction tx = null;
   try{
     tx = session.beginTransaction();
     String sql = "SELECT * FROM EMPLOYEE";
     SQLQuery query = session.createSQLQuery(sql);
     query.addEntity(Employee.class);
     List employees = query.list();
 
     for (Iterator iterator =
              employees.iterator(); iterator.hasNext();){
      Employee employee = (Employee) iterator.next();
      System.out.print("First Name: " + employee.getFirstName());
      System.out.print(" Last Name: " + employee.getLastName());
      System.out.println(" Salary: " + employee.getSalary());
     }
     tx.commit();
   }catch (HibernateException e) {
     if (tx!=null) tx.rollback();
     e.printStackTrace();
   }finally {
     session.close();
   }
  }
}

编译和执行:
下面是步骤来编译并运行上述应用程序。请确保在进行的编译和执行之前,适当地设置PATH和CLASSPATH。

执行ManageEmployee二进制文件来运行程序。

会得到以下结果,并记录将在EMPLOYEE表中创建。

$java ManageEmployee
.......VARIOUS LOG MESSAGES WILL DISPLAY HERE........
 
First Name: Zara, Salary: 2000
First Name: Daisy, Salary: 5000
First Name: John, Salary: 5000
First Name: Mohd, Salary: 3000
First Name: Zara Last Name: Ali Salary: 2000
First Name: Daisy Last Name: Das Salary: 5000
First Name: John Last Name: Paul Salary: 5000
First Name: Mohd Last Name: Yasee Salary: 3000

如果检查EMPLOYEE表,它应该记录下已:

mysql> select * from EMPLOYEE;
+----+------------+-----------+--------+
| id | first_name | last_name | salary |
+----+------------+-----------+--------+
| 26 | Zara    | Ali    |  2000 |
| 27 | Daisy   | Das    |  5000 |
| 28 | John    | Paul   |  5000 |
| 29 | Mohd    | Yasee   |  3000 |
+----+------------+-----------+--------+
4 rows in set (0.00 sec)

更多Explication détaillée de la mise en cache et de lutilisation dinstructions SQL natives dans le framework Hibernate de Java相关文章请关注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