ホームページ  >  記事  >  Java  >  Java の Hibernate フレームワークにおけるアノテーションとキャッシュの詳細な説明

Java の Hibernate フレームワークにおけるアノテーションとキャッシュの詳細な説明

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

アノテーション
Hibernate アノテーションは、XML ファイルを使用せずにマッピングを定義する新しい方法です。 XML マッピング メタデータに加えて、または XML マッピング メタデータの置換に注釈を使用できます。

Hibernate アノテーションは、メタデータ オブジェクトとリレーショナル テーブルのマッピングを提供する強力な方法です。すべてのメタデータは POJO Java ファイルのコードにまとめられており、開発プロセス中にユーザーがテーブル構造と POJO の両方を理解するのに役立ちます。

アプリケーションを他の EJB3 仕様 ORM アプリケーションに移植する予定がある場合は、アノテーションを使用してマッピング情報を表現する必要がありますが、より高い柔軟性が必要な場合は、XML ベースのマッピングを使用する必要があります。

Hibernate アノテーションの環境設定
まず第一に、JDK5.0 を使用していることを確認する必要があります。そうでない場合は、アノテーションのネイティブ サポートを利用するには、JDK を JDK5.0 にアップグレードする必要があります。

次に、Hibernate 3.x アノテーション配布パッケージをインストールする必要があります。これは SourceForge から入手できます: (Hibernate Annotation をダウンロード)、hibernate-annotations.jar、lib/hibernate-comons-annotations.jar、lib/ejb3 をコピーします。 -persistence.jar Hibernate アノテーションから CLASSPATH へのクラス インスタンスの割り当て

アノテーション:
Hibernate アノテーションを使用した作業中に述べたように、すべてのメタデータは上記のコードとともに POJO Java ファイルに取り込まれます。これは、ユーザーがテーブル構造を同時に理解するのに役立ちます。開発中とPOJO。

次の 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)
);

以下は、定義された EMPLOYEE テーブルのオブジェクトをマップするためにアノテーションを使用した Employee クラスのマッピングです:

import javax.persistence.*;
 
@Entity
@Table(name = "EMPLOYEE")
public class Employee {
  @Id @GeneratedValue
  @Column(name = "id")
  private int id;
 
  @Column(name = "first_name")
  private String firstName;
 
  @Column(name = "last_name")
  private String lastName;
 
  @Column(name = "salary")
  private int salary;
 
  public Employee() {}
  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;
  }
}

Hibernate は、 @Id アノテーションが正しい フィールドは、実行時にドメインを介して直接アクセスする必要があるオブジェクトのプロパティであると想定されます。 getId() メソッドに @Id アノテーションを付けると、ゲッター メソッドとセッター メソッドを介したプロパティへのアクセスがデフォルトで許可されます。したがって、他のすべてのアノテーションも、選択された戦略に従ってフィールドまたはゲッター メソッドに配置されます。次のセクションでは、上記のクラスで使用されるアノテーションについて説明します。

@Entity 注:
EJB3 仕様は javax.persistence パッケージに含まれているため、最初のステップとしてこのパッケージをインポートします。次に、 @Entity アノテーションを使用して、このクラスをエンティティ Bean Employee クラスとしてマークしました。そのため、このクラスには、保護されたスコープで最終的に表示されるパラメーターなしのコンストラクターが必要です。

@Table アノテーション:
@Table アノテーションを使用すると、このエンティティの詳細をデータベースに保存するために使用されるテーブルを指定できます。

@Table アノテーションには、テーブルの名前、カタログ、スキーマをオーバーライドしたり、テーブル内の列に一意の制約を強制したりできる 4 つのプロパティが用意されています。ここでは、先ほど指定した EMPLOYEE テーブルの名前を使用します。

@Id および @GeneratedValue アノテーション:
各エンティティ Bean には、クラスの @Id アノテーションでアノテーションが付けられた主キーがあります。主キーは、テーブル構造に応じて、単一のフィールドまたは複数のフィールドの組み合わせになります。

デフォルトでは、@Id アノテーションは、使用する最も適切な主キー生成戦略を自動的に決定しますが、@GeneratedValue アノテーションを適用することで使用できます。このアノテーションは、戦略とジェネレーターの 2 つのパラメーターを受け入れますが、これらについては説明しません。ここでは、デフォルトの Default キー生成戦略を使用するだけです。 Hibernate に使用するジェネレーターのタイプを決定させることで、異なるデータベース間でコードを移植できるようになります。

@Column 注釈:
@Column 注釈は、フィールドまたは属性がマップされる列の詳細を指定するために使用されます。以下の最も一般的に使用される属性は、列の注釈で使用できます:

name 属性を使用すると、列の名前を明示的に指定できます。

length 属性を使用すると、列のサイズを使用して値、特に文字列値をマップできます。

nullable 属性を使用すると、スキーマの生成時に列を NOT NULL としてマークできます。

unique 属性を使用すると、列に一意の値のみを含むものとしてマークを付けることができます。

アプリケーション クラスの作成:
最後に、アプリケーションを実行するためのアプリケーション クラスの main() メソッドを作成します。このアプリケーションを使用していくつかの従業員レコードを保存し、そのレコードに CRUD 操作を適用します。

import java.util.List;
import java.util.Date;
import java.util.Iterator;
  
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
 
public class ManageEmployee {
  private static SessionFactory factory;
  public static void main(String[] args) {
   try{
     factory = new AnnotationConfiguration().
          configure().
          //addPackage("com.xyz") //add package if used.
          addAnnotatedClass(Employee.class).
          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", 1000);
   Integer empID2 = ME.addEmployee("Daisy", "Das", 5000);
   Integer empID3 = ME.addEmployee("John", "Paul", 10000);
 
   /* List down all the employees */
   ME.listEmployees();
 
   /* Update employee's records */
   ME.updateEmployee(empID1, 5000);
 
   /* Delete an employee from the database */
   ME.deleteEmployee(empID2);
 
   /* List down new list of the employees */
   ME.listEmployees();
  }
  /* 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();
     employee.setFirstName(fname);
     employee.setLastName(lname);
     employee.setSalary(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 */
  public void listEmployees( ){
   Session session = factory.openSession();
   Transaction tx = null;
   try{
     tx = session.beginTransaction();
     List employees = session.createQuery("FROM Employee").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();
   }
  }
  /* Method to UPDATE salary for an employee */
  public void updateEmployee(Integer EmployeeID, int salary ){
   Session session = factory.openSession();
   Transaction tx = null;
   try{
     tx = session.beginTransaction();
     Employee employee =
          (Employee)session.get(Employee.class, EmployeeID);
     employee.setSalary( salary );
  session.update(employee);
     tx.commit();
   }catch (HibernateException e) {
     if (tx!=null) tx.rollback();
     e.printStackTrace();
   }finally {
     session.close();
   }
  }
  /* Method to DELETE an employee from the records */
  public void deleteEmployee(Integer EmployeeID){
   Session session = factory.openSession();
   Transaction tx = null;
   try{
     tx = session.beginTransaction();
     Employee employee =
          (Employee)session.get(Employee.class, EmployeeID);
     session.delete(employee);
     tx.commit();
   }catch (HibernateException e) {
     if (tx!=null) tx.rollback();
     e.printStackTrace();
   }finally {
     session.close();
   }
  }
}

データベース設定:
次に、hibernate.cfg.xml 設定ファイルを作成して、データベースの関連パラメーターを定義しましょう。

<?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">
   cohondob
  </property>
 
</session-factory>
</hibernate-configuration>

コンパイルと実行:
上記のアプリケーションをコンパイルして実行する手順は次のとおりです。コンパイルと実行の前に、PATH と CLASSPATH が適切に設定されていることを確認してください。

Employee.hbm.xml マッピング ファイルをパスから削除します。

上記のように Employee.java ソース ファイルを作成し、コンパイルします。

上記のように ManageEmployee.java ソース ファイルを作成し、コンパイルします。

ManageEmployee バイナリを実行してプログラムを実行します。

次の結果が取得され、EMPLOYEE テーブルに記録されます。

$java ManageEmployee
.......VARIOUS LOG MESSAGES WILL DISPLAY HERE........
 
First Name: Zara Last Name: Ali Salary: 1000
First Name: Daisy Last Name: Das Salary: 5000
First Name: John Last Name: Paul Salary: 10000
First Name: Zara Last Name: Ali Salary: 5000
First Name: John Last Name: Paul Salary: 10000

EMPLOYEE テーブルをチェックすると、次のレコードがあるはずです:

mysql> select * from EMPLOYEE;
+----+------------+-----------+--------+
| id | first_name | last_name | salary |
+----+------------+-----------+--------+
| 29 | Zara    | Ali    |  5000 |
| 31 | John    | Paul   | 10000 |
+----+------------+-----------+--------+
2 rows in set (0.00 sec
 
mysql>

キャッシュ
キャッシュはアプリケーションのパフォーマンスの最適化を目的としており、データベースへの複数回のアクセスを避けるためにアプリケーションとデータベースの間に配置されます。パフォーマンス重視タイプのアプリケーションのパフォーマンスは向上します。

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

第一级缓存:
第一级缓存是Session的缓存,是一个强制性的缓存,通过它所有的请求都必须通过。 Session对象不断自身的动力的对象,提交到数据库之前。

如果发出多个更新一个对象,Hibernate试图拖延尽可能长的时间做了更新,以减少发出的更新SQL语句的数量。如果您关闭会话,所有被缓存的对象都将丢失,要么持久,或在数据库中更新。

二级缓存:
二级缓存是可选的缓存和一级缓存,总是会征询任何试图找到一个对象的二级缓存之前。第二级缓存可以在每个类和每个集合基础上进行配置,主要负责在会话缓存的对象。

任何第三方缓存可以使用Hibernate。org.hibernate.cache.CacheProvider接口提供,必须实施提供Hibernate一个句柄缓存实现。

查询级别缓存:
Hibernate也实现了查询结果集缓存与二级缓存的紧密集成在一起。

这是一个可选功能,需要两个额外的物理缓存中保存缓存的查询结果和地区当一个表的最后更新的时间戳。这只是针对那些使用相同的参数经常运行的查询非常有用。

二级缓存:
Hibernate使用一级缓存,默认情况下,你什么都没有做使用第一级缓存。让我们直接进入可选的第二级缓存。并不是所有的类受益于缓存,这样一来就能禁用二级缓存是很重要的

Hibernate二级缓存被设置为两个步骤。首先,必须决定要使用的并发策略。在此之后,可以配置缓存过期和使用缓存提供物理缓存属性。

并发策略:
并发策略是一个中介的负责存储数据项在缓存并从缓存中检索它们。如果要启用二级缓存,将必须决定,为每个持久化类和集合,要使用的缓存并发策略。

Transactional: 使用这种策略的主要读取数据的地方,以防止过时的数据的并发事务,在更新的罕见情况下是至关重要的。

Read-write: 再次使用这种策略的主要读取数据的地方,以防止并发事务陈旧的数据是至关重要的,在更新的罕见情况。

Nonstrict-read-write: 这种策略不保证缓存与数据库之间的一致性。使用此策略,如果数据很少改变和陈旧数据的可能性很小关键是不关注。

Read-only: 并发策略适用于数据,永远不会改变。使用数据仅供参考。

如果我们要使用第二级缓存为我们的Employee类,让我们添加告诉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>

 usage="read-write" 属性告诉Hibernate使用一个可读写的并发策略定义的缓存。

缓存提供者:
考虑到会用你的缓存候选类的并发策略后,下一步就是选择一个缓存提供程序。Hibernate迫使选择一个缓存提供整个应用程序。

Java の Hibernate フレームワークにおけるアノテーションとキャッシュの詳細な説明

在指定hibernate.cfg.xml配置文件中的缓存提供。选择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类的二级缓存和Hibernate现在二级缓存,每当浏览到一个雇员或当通过标识符加载雇员。

应该分析你所有的类,并选择适当的缓存策略为每个类。有时,二级缓存可能降级的应用程序的性能。所以建议到基准应用程序第一次没有启用缓存,非常适合缓存和检查性能。如果缓存不提高系统性能再有就是在使任何类型的缓存是没有意义的。

查询级别缓存:
使用查询缓存,必须先使用 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();

このコードはメソッドを使用して、クエリの従業員側をキャッシュ。

Java の Hibernate フレームワークにおけるアノテーションとキャッシュに関する詳細な記事については、PHP 中国語 Web サイトに注目してください。

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