ホームページ  >  記事  >  Java  >  Java の Hibernate フレームワークにおけるキャッシュとネイティブ SQL ステートメントの使用の詳細な説明

Java の Hibernate フレームワークにおけるキャッシュとネイティブ SQL ステートメントの使用の詳細な説明

高洛峰
高洛峰オリジナル
2017-01-23 11:48:481027ブラウズ

Hibernate Cache
キャッシュはアプリケーションのパフォーマンスを最適化するためのものであり、アプリケーションとデータベースの間に配置され、複数のデータベース アクセスを回避し、パフォーマンスが重要なアプリケーションのパフォーマンスを向上させます。

キャッシュは Hibernate にとって非常に重要です。以下に説明するように、マルチレベル キャッシュ スキームが採用されています。

Java の Hibernate フレームワークにおけるキャッシュとネイティブ SQL ステートメントの使用の詳細な説明

一次キャッシュ:
一次キャッシュはセッション キャッシュであり、すべてのキャッシュが通過する必須のキャッシュです。すべてのリクエストを通過する必要があります。 Session オブジェクトは、データベースに送信される前に、独自のパワー オブジェクトを保持します。

オブジェクトに対して複数の更新が発行される場合、Hibernate は発行される更新 SQL ステートメントの数を減らすために、可能な限り更新を遅らせようとします。セッションを閉じると、キャッシュされたオブジェクトはすべて失われ、データベース内で永続化または更新されます。

レベル 2 キャッシュ:
レベル 2 キャッシュはオプションのキャッシュであり、L2 キャッシュ内のオブジェクトを検索する前に常に L1 キャッシュが参照されます。第 2 レベルのキャッシュはクラスごとおよびコレクションごとに構成でき、セッション内のオブジェクトをキャッシュします。

どのサードパーティのキャッシュでも Hibernate を使用できます。 org.hibernate.cache.CacheProvider インターフェースは、Hibernate を提供するために実装する必要があるハンドル・キャッシュ実装を提供します。

クエリ レベル キャッシュ:
Hibernate は、クエリ結果セット キャッシュと二次キャッシュの緊密な統合も実現します。

これは、キャッシュされたクエリ結果とテーブルが最後に更新されたときのタイムスタンプを保持するために 2 つの追加の物理キャッシュを必要とするオプションの機能です。これは、同じパラメータを使用して頻繁に実行されるクエリにのみ役立ちます。

レベル 2 キャッシュ:
Hibernate は 1 レベル キャッシュを使用します。デフォルトでは、1 レベル キャッシュを使用するために何もしません。オプションの 2 次キャッシュに早速入ってみましょう。すべてのクラスがキャッシュの恩恵を受けるわけではないため、2 次キャッシュを無効にできることが重要です

Hibernate の 2 次キャッシュは 2 段階のプロセスとして設定されます。まず、使用する同時実行戦略を決定する必要があります。この後、キャッシュの有効期限を構成し、キャッシュ プロビジョニングの物理キャッシュ プロパティを使用できます。

同時実行戦略:
同時実行戦略は、データ項目をキャッシュに保存し、キャッシュから取得する役割を担う仲介者です。第 2 レベルのキャッシュを有効にする場合は、永続クラスとコレクションごとに、使用するキャッシュ同時実行戦略を決定する必要があります。

トランザクション: メインの読み取りデータが古いデータの同時トランザクションを防ぐことである場合、この戦略を使用します。これは、まれな更新の場合に重要です。

読み取り/書き込み: まれに更新される場合に、古いデータによる同時トランザクションを防ぐことが重要な場合は、主にデータを読み取るためにこの戦略を使用します。

非厳密読み取り書き込み: この戦略は、キャッシュとデータベース間の一貫性を保証しません。データがほとんど変更されず、データが古い可能性が低い場合、この戦略を使用することは重要ではありません。

読み取り専用: 同時実行戦略はデータに適用され、変更されることはありません。使用状況データは参考用です。

Employee クラスに第 2 レベルのキャッシュを使用する場合は、Hibernate に 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>

use="read-write" 属性は、読み取り/書き込み同時実行戦略によって定義されたキャッシュを使用するように Hibernate に指示します。

キャッシュ プロバイダー:
キャッシュ候補クラスを使用する同時実行戦略を検討した後の次のステップは、キャッシュ プロバイダーを選択することです。 Hibernate では、アプリケーション全体にサービスを提供するために 1 つのキャッシュの選択が強制されます。

Java の Hibernate フレームワークにおけるキャッシュとネイティブ SQL ステートメントの使用の詳細な説明

指定された hibernate.cfg.xml 設定ファイルでのキャッシュのプロビジョニング。第 2 レベルのキャッシュ プロバイダーとして EHCache を選択します:

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

ここで、キャッシュ領域のプロパティを指定する必要があります。 EHCache には独自の構成ファイル ehcache.xml があり、アプリケーションの CLASSPATH にあります。 ehcache.xml の Employee クラスのキャッシュ設定は次のようになります:

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

これで、Employee クラスの 2 番目のレベルのキャッシュを有効にします。これで、従業員が参照されるとき、または従業員がロードされるときに Hibernate が 2 番目のレベルのキャッシュを保持するようになります。識別子によって。

はすべてのクラスを分析し、各クラスに適切なキャッシュ戦略を選択する必要があります。場合によっては、2 次キャッシュによってアプリケーションのパフォーマンスが低下することがあります。したがって、キャッシュを有効にせずに初めてアプリケーションのベンチマークを実行することをお勧めします。これは、キャッシュとパフォーマンスのチェックに最適です。キャッシュによってシステムのパフォーマンスが向上しない場合は、どのような種類のキャッシュを使用しても意味がありません。

クエリ レベル キャッシュ:
クエリ キャッシュを使用するには、まず構成ファイル内で hibernate.cache.use_query_cache="true" プロパティを使用して有効にする必要があります。このプロパティを true に設定すると、Hibernate はクエリと識別子セットを保持するために必要なキャッシュをメモリ内に作成します。

次に、クエリ キャッシュを使用するには、Query クラスの setCacheable(Boolean) メソッドを使用します。例:

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)

更多Java の Hibernate フレームワークにおけるキャッシュとネイティブ SQL ステートメントの使用の詳細な説明相关文章请关注PHP中文网!

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。