Hibernate-quick-guide

提供:Dev Guides
移動先:案内検索

Hibernate-ORMの概要

JDBCとは

JDBCは Java Database Connectivity の略です。 JavaプログラムからリレーショナルデータベースにアクセスするためのJava APIのセットを提供します。 これらのJava APIにより、JavaプログラムはSQLステートメントを実行し、SQL準拠のデータベースと対話できます。

JDBCは、さまざまなプラットフォームで実行でき、修正なしでさまざまなDBMSと対話できるデータベースに依存しないアプリケーションを作成するための柔軟なアーキテクチャを提供します。

JDBCの長所と短所

Pros of JDBC Cons of JDBC

Clean and simple SQL processing

大きなデータで良好なパフォーマンス

小規模なアプリケーションに非常に適しています

習得が簡単なシンプルな構文

a

大規模プロジェクトで使用される場合は複雑

大きなプログラミングオーバーヘッド

カプセル化なし

実装が難しいMVCコンセプト

クエリはDBMS固有です

なぜオブジェクトリレーショナルマッピング(ORM)なのか?

オブジェクト指向システムで作業する場合、オブジェクトモデルとリレーショナルデータベースの間に不一致があります。 RDBMSはデータを表形式で表しますが、JavaやC#などのオブジェクト指向言語は相互接続されたオブジェクトのグラフとして表されます。

適切なコンストラクタと関連するパブリック関数を持つ次のJavaクラスを検討してください-

public class Employee {
   private int id;
   private String first_name;
   private String last_name;
   private int salary;

   public Employee() {}
   public Employee(String fname, String lname, int salary) {
      this.first_name = fname;
      this.last_name = lname;
      this.salary = salary;
   }

   public int getId() {
      return id;
   }

   public String getFirstName() {
      return first_name;
   }

   public String getLastName() {
      return last_name;
   }

   public int getSalary() {
      return salary;
   }
}

上記のオブジェクトは、次のRDBMSテーブルに格納および取得されることを考慮してください-

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

最初の問題は、数ページまたはアプリケーションを開発した後にデータベースの設計を変更する必要がある場合はどうなるでしょうか? 第二に、リレーショナルデータベースにオブジェクトをロードして保存すると、次の5つの不一致の問題が発生します。

Sr.No. Mismatch & Description
1

Granularity

オブジェクトモデルには、データベース内の対応するテーブルの数よりも多くのクラスがある場合があります。

2

Inheritance

RDBMSは、オブジェクト指向プログラミング言語の自然なパラダイムである継承に似たものを定義しません。

3

Identity

RDBMSは、「同一性」という1つの概念、つまり主キーを正確に定義します。 ただし、Javaは、オブジェクトの同一性(a == b)とオブジェクトの同等性(a.equals(b))の両方を定義します。

4

Associations

オブジェクト指向言語は、オブジェクト参照を使用して関連付けを表しますが、RDBMSは外部キー列として関連付けを表します。

5

Navigation

JavaとRDBMSでオブジェクトにアクセスする方法は根本的に異なります。

  • O * bject-* R elational M * apping(ORM)は、上記のすべてのインピーダンス不整合を処理するソリューションです。

ORMとは何ですか?

ORMは* O * bject-* R elational M * apping(ORM)の略で、リレーショナルデータベースとJava、C#などのオブジェクト指向プログラミング言語との間でデータを変換するためのプログラミング手法です。

ORMシステムには、プレーンJDBCよりも次の利点があります-

Sr.No. Advantages
1 Let’s business code access objects rather than DB tables.
2 Hides details of SQL queries from OO logic.
3 Based on JDBC 'under the hood.'
4 No need to deal with the database implementation.
5 Entities based on business concepts rather than database structure.
6 Transaction management and automatic key generation.
7 Fast development of application.

ORMソリューションは、次の4つのエンティティで構成されています-

Sr.No. Solutions
1 An API to perform basic CRUD operations on objects of persistent classes.
2 A language or API to specify queries that refer to classes and properties of classes.
3 A configurable facility for specifying mapping metadata.
4 A technique to interact with transactional objects to perform dirty checking, lazy association fetching, and other optimization functions.

Java ORMフレームワーク

Javaには、いくつかの永続的なフレームワークとORMオプションがあります。 永続フレームワークは、オブジェクトをリレーショナルデータベースに格納および取得するORMサービスです。

  • エンタープライズJavaBeanエンティティBean
  • Javaデータオブジェクト
  • キャスター
  • TopLink
  • 春のDAO
  • 休止状態
  • などなど

Hibernate-概要

Hibernateは、JAVA用の* O * bject-* R elational M * apping(ORM)ソリューションです。 これは、2001年にGavin Kingによって作成されたオープンソースの永続的なフレームワークです。 これは、あらゆるJavaアプリケーション向けの強力で高性能なオブジェクトリレーショナル永続性およびクエリサービスです。

HibernateはJavaクラスをデータベーステーブルにマッピングし、Javaデータ型からSQLデータ型にマッピングし、一般的なデータ永続性に関連するプログラミングタスクの95%から開発者を解放します。

Hibernateは、従来のJavaオブジェクトとデータベースサーバーの間に位置し、適切なO/Rメカニズムとパターンに基づいてこれらのオブジェクトを永続化するすべての作業を処理します。

休止状態の位置

Hibernateの利点

  • Hibernateは、XMLファイルを使用して、コードを一切記述することなく、Javaクラスをデータベーステーブルにマッピングします。
  • Javaオブジェクトをデータベースと直接やり取りするためのシンプルなAPIを提供します。
  • データベースまたはテーブルに変更がある場合は、XMLファイルプロパティのみを変更する必要があります。
  • なじみのないSQL型を抽象化し、おなじみのJavaオブジェクトを回避する方法を提供します。
  • Hibernateは動作するためにアプリケーションサーバーを必要としません。
  • データベースのオブジェクトの複雑な関連付けを操作します。
  • スマートフェッチ戦略でデータベースアクセスを最小限に抑えます。
  • データの簡単なクエリを提供します。

サポートされているデータベース

Hibernateは、ほぼすべての主要なRDBMSをサポートしています。 以下は、Hibernateがサポートするデータベースエンジンのいくつかのリストです-

  • HSQLデータベースエンジン
  • DB2/NT
  • MySQL
  • PostgreSQL
  • FrontBase
  • オラクル
  • Microsoft SQL Serverデータベース
  • Sybase SQL Server
  • Informix Dynamic Server

サポートされている技術

Hibernateは、以下を含む他のさまざまなテクノロジーをサポートしています-

  • XDoclet Spring
  • J2EE
  • Eclipseプラグイン
  • メーベン

Hibernate-アーキテクチャ

Hibernateには階層化されたアーキテクチャがあり、ユーザーが基になるAPIを知らなくても操作できるようにします。 Hibernateはデータベースと設定データを利用して、アプリケーションに永続サービス(および永続オブジェクト)を提供します。

以下は、Hibernate Application Architectureの非常に高レベルのビューです。

Hibernate High Level View

以下は、重要なコアクラスを備えたHibernate Application Architectureの詳細ビューです。

Hibernateアーキテクチャ

Hibernateは、JDBC、Java Transaction API(JTA)、Java Naming and Directory Interface(JNDI)などのさまざまな既存のJava APIを使用します。 JDBCは、リレーショナルデータベースに共通する機能の基本レベルの抽象化を提供し、JDBCドライバーを備えたほとんどすべてのデータベースをHibernateでサポートできます。 JNDIおよびJTAを使用すると、HibernateをJ2EEアプリケーションサーバーと統合できます。

次のセクションでは、Hibernate Application Architectureに含まれる各クラスオブジェクトについて簡単に説明します。

構成オブジェクト

Configurationオブジェクトは、Hibernateアプリケーションで作成する最初のHibernateオブジェクトです。 通常、アプリケーションの初期化中に一度だけ作成されます。 Hibernateが必要とする設定ファイルまたはプロパティファイルを表します。

構成オブジェクトは、2つのキーコンポーネントを提供します-

  • データベース接続-これは、Hibernateでサポートされている1つ以上の構成ファイルを介して処理されます。 これらのファイルは hibernate.properties および hibernate.cfg.xml です。
  • クラスマッピングのセットアップ-このコンポーネントは、Javaクラスとデータベーステーブル間の接続を作成します。

SessionFactoryオブジェクト

構成オブジェクトを使用してSessionFactoryオブジェクトを作成します。これにより、提供された構成ファイルを使用してアプリケーションのHibernateが構成され、Sessionオブジェクトをインスタンス化できます。 SessionFactoryはスレッドセーフオブジェクトであり、アプリケーションのすべてのスレッドで使用されます。

SessionFactoryは重量のあるオブジェクトです。通常、アプリケーションの起動時に作成され、後で使用するために保持されます。 別の構成ファイルを使用して、データベースごとに1つのSessionFactoryオブジェクトが必要になります。 したがって、複数のデータベースを使用している場合は、複数のSessionFactoryオブジェクトを作成する必要があります。

セッションオブジェクト

セッションは、データベースとの物理的な接続を取得するために使用されます。 Sessionオブジェクトは軽量で、データベースとの対話が必要になるたびにインスタンス化されるように設計されています。 永続オブジェクトは、Sessionオブジェクトを介して保存および取得されます。

セッションオブジェクトは、通常はスレッドセーフではないため、長時間開いたままにしないでください。また、必要に応じて作成および破棄する必要があります。

トランザクションオブジェクト

トランザクションはデータベースの作業単位を表し、ほとんどのRDBMSはトランザクション機能をサポートします。 Hibernateのトランザクションは、基になるトランザクションマネージャーとトランザクション(JDBCまたはJTAから)によって処理されます。

これはオプションのオブジェクトであり、Hibernateアプリケーションはこのインターフェイスを使用しないことを選択でき、代わりに独自のアプリケーションコードでトランザクションを管理します。

クエリオブジェクト

クエリオブジェクトは、SQLまたはHibernate Query Language(HQL)文字列を使用して、データベースからデータを取得し、オブジェクトを作成します。 Queryインスタンスは、クエリパラメータをバインドし、クエリによって返される結果の数を制限し、最後にクエリを実行するために使用されます。

基準オブジェクト

Criteriaオブジェクトを使用して、オブジェクト指向の条件クエリを作成および実行し、オブジェクトを取得します。

Hibernate-環境

この章では、Hibernateおよびその他の関連パッケージをインストールして、Hibernateアプリケーションの環境を準備する方法について説明します。 MySQLデータベースを使用してHibernateの例を試すため、MySQLデータベースのセットアップが既にあることを確認してください。 MySQLの詳細については、リンク:/mysql/index [MySQLチュートリアル]を確認してください。

Hibernateをダウンロードする

システムにJavaの最新バージョンが既にインストールされていることを前提としています。 以下は、システムにHibernateをダウンロードしてインストールする簡単な手順です-

  • HibernateをWindowsにインストールするか、Unixにインストールするかを選択してから、次のステップに進み、Windows用の.zipファイルとUnix用の.tzファイルをダウンロードします。
  • [[1]]
  • このチュートリアルを書いている時点で、 hibernate-distribution3.6.4.Final をダウンロードしました。ダウンロードしたファイルを解凍すると、次の画像に示すようなディレクトリ構造が得られます。

Hibernateディレクトリ

Hibernateのインストール

Hibernateインストールファイルの最新バージョンをダウンロードして解凍したら、次の2つの簡単な手順を実行する必要があります。 CLASSPATH変数を適切に設定していることを確認してください。正しく設定しないと、アプリケーションのコンパイル中に問題が発生します。

  • 今、すべてのライブラリファイルを /lib からCLASSPATHにコピーし、すべてのJARを含むようにクラスパス変数を変更します-
  • 最後に、 hibernate3.jar ファイルをCLASSPATHにコピーします。 このファイルはインストールのルートディレクトリにあり、Hibernateが作業を行うために必要なプライマリJARです。

Hibernateの前提条件

Hibernateに必要なパッケージ/ライブラリのリストを以下に示します。Hibernateを開始する前にインストールする必要があります。 これらのパッケージをインストールするには、ライブラリファイルを /lib からCLASSPATHにコピーし、それに応じてCLASSPATH変数を変更する必要があります。

Sr.No. Packages/Libraries
1

dom4j

XML解析http://www.dom4j.org/[www.dom4j.org/]

2

Xalan

XSLTプロセッサーhttps://xml.apache.org/xalan-j/

3

Xerces

Xerces Javaパーサーhttps://xml.apache.org/xerces-j/

4

cglib

実行時のJavaクラスへの適切な変更http://cglib.sourceforge.net/

5

log4j

Faremworkのログhttps://logging.apache.org/log4j

6

Commons

ロギング、メールなど https://jakarta.apache.org/commons

7

SLF4J

Java用Logging Facade https://www.slf4j.org

Hibernate-設定

Hibernateは事前に知る必要があります— Javaクラスがデータベーステーブルにどのように関連するかを定義するマッピング情報をどこで見つけるか。 Hibernateには、データベースおよびその他の関連パラメーターに関連する一連の構成設定も必要です。 このような情報はすべて、通常 hibernate.properties という標準のJavaプロパティファイルとして、または hibernate.cfg.xml という名前のXMLファイルとして提供されます。

私の例では、必要なHibernateプロパティを指定するために、XML形式のファイル hibernate.cfg.xml を検討します。 ほとんどのプロパティはデフォルト値を使用するため、実際に必要な場合を除き、プロパティファイルで指定する必要はありません。 このファイルは、アプリケーションのクラスパスのルートディレクトリに保持されます。

休止状態のプロパティ

以下は、重要なプロパティのリストです。スタンドアロンの状況でデータベースを構成する必要があります-

Sr.No. Properties & Description
1

hibernate.dialect

このプロパティにより、Hibernateは選択したデータベースに適切なSQLを生成します。

2

hibernate.connection.driver_class

JDBCドライバークラス。

3

hibernate.connection.url

データベースインスタンスへのJDBC URL。

4

hibernate.connection.username

データベースのユーザー名。

5

hibernate.connection.password

データベースのパスワード。

6

hibernate.connection.pool_size

Hibernateデータベース接続プールで待機している接続の数を制限します。

7

hibernate.connection.autocommit

JDBC接続に自動コミットモードを使用できるようにします。

あなたがアプリケーションサーバーとJNDIと一緒にデータベースを使用している場合は、次のプロパティを設定する必要があります-

Sr.No. Properties & Description
1

hibernate.connection.datasource

アプリケーションに使用しているアプリケーションサーバーコンテキストで定義されたJNDI名。

2

hibernate.jndi.class

JNDIのInitialContextクラス。

3

hibernate.jndi.<JNDIpropertyname>

任意のJNDIプロパティをJNDI _InitialContext_に渡します。

4

hibernate.jndi.url

JNDIのURLを提供します。

5

hibernate.connection.username

データベースのユーザー名。

6

hibernate.connection.password

データベースのパスワード。

MySQLデータベースを使用したHibernate

MySQLは、現在利用可能な最も人気のあるオープンソースデータベースシステムの1つです。 hibernate.cfg.xml 構成ファイルを作成し、アプリケーションのクラスパスのルートに配置しましょう。 MySQLデータベースで testdb データベースが使用可能であり、データベースにアクセスするためのユーザー test が使用可能であることを確認する必要があります。

XML構成ファイルは、http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtdで入手可能なHibernate 3構成DTDに準拠する必要があります。

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

      <!-- List of XML mapping files -->
      <mapping resource = "Employee.hbm.xml"/>

   </session-factory>
</hibernate-configuration>

上記の構成ファイルには <mapping> タグが含まれており、これはhibernatemappingファイルに関連しています。次の章では、hibernateマッピングファイルとは何か、どのように、そしてなぜ使用するのかを説明します。

以下は、さまざまな重要なデータベースの方言プロパティタイプのリストです-

Sr.No. Database & Dialect Property
1

DB2

org.hibernate.dialect.DB2Dialect

2

HSQLDB

org.hibernate.dialect.HSQLDialect

3

HypersonicSQL

org.hibernate.dialect.HSQLDialect

4

Informix

org.hibernate.dialect.InformixDialect

5

Ingres

org.hibernate.dialect.IngresDialect

6

Interbase

org.hibernate.dialect.InterbaseDialect

7

Microsoft SQL Server 2000

org.hibernate.dialect.SQLServerDialect

8

Microsoft SQL Server 2005

org.hibernate.dialect.SQLServer2005Dialect

9

Microsoft SQL Server 2008

org.hibernate.dialect.SQLServer2008Dialect

10

MySQL

org.hibernate.dialect.MySQLDialect

11

Oracle (any version)

org.hibernate.dialect.OracleDialect

12

Oracle 11g

org.hibernate.dialect.Oracle10gDialect

13

Oracle 10g

org.hibernate.dialect.Oracle10gDialect

14

Oracle 9i

org.hibernate.dialect.Oracle9iDialect

15

PostgreSQL

org.hibernate.dialect.PostgreSQLDialect

16

Progress

org.hibernate.dialect.ProgressDialect

17

SAP DB

org.hibernate.dialect.SAPDBDialect

18

Sybase

org.hibernate.dialect.SybaseDialect

19

Sybase Anywhere

org.hibernate.dialect.SybaseAnywhereDialect

Hibernate-セッション

セッションは、データベースとの物理的な接続を取得するために使用されます。 Sessionオブジェクトは軽量で、データベースとの対話が必要になるたびにインスタンス化されるように設計されています。 永続オブジェクトは、Sessionオブジェクトを介して保存および取得されます。

セッションオブジェクトは、通常はスレッドセーフではないため、長時間開いたままにしないでください。また、必要に応じて作成および破棄する必要があります。 セッションの主な機能は、マップされたエンティティクラスのインスタンスの操作を提供、作成、読み取り、および削除することです。

インスタンスは、特定の時点で次の3つの状態のいずれかに存在する場合があります-

  • transient -Sessionに関連付けられておらず、データベース内に表現がなく、Hibernateによって識別子値が一時的であると見なされない永続クラスの新しいインスタンス。
  • persistent -Sessionに関連付けることで一時的なインスタンスを永続化できます。 永続インスタンスは、データベース内の表現、識別子の値を持ち、セッションに関連付けられます。
  • detached -Hibernate Sessionを閉じると、永続インスタンスは切り離されたインスタンスになります。

永続クラスがシリアル化可能な場合、Sessionインスタンスはシリアル化可能です。 典型的なトランザクションは、次のイディオムを使用する必要があります-

Session session = factory.openSession();
Transaction tx = null;

try {
   tx = session.beginTransaction();
  //do some work
   ...
   tx.commit();
}

catch (Exception e) {
   if (tx!=null) tx.rollback();
   e.printStackTrace();
} finally {
   session.close();
}

セッションが例外をスローした場合、トランザクションをロールバックし、セッションを破棄する必要があります。

セッションインターフェイスメソッド

*Session* インターフェースによって提供されるメソッドは多数ありますが、このチュートリアルで使用するいくつかの重要なメソッドのみをリストアップします。 *Session* および *SessionFactory* に関連付けられたメソッドの完全なリストについては、Hibernateのドキュメントを確認できます。
Sr.No. Session Methods & Description
1

Transaction beginTransaction()

作業単位を開始し、関連するTransactionオブジェクトを返します。

2

void cancelQuery()

現在のクエリの実行をキャンセルします。

3

void clear()

セッションを完全にクリアします。

4

Connection close()

JDBC接続を解放してクリーンアップすることにより、セッションを終了します。

5

Criteria createCriteria(Class persistentClass)

特定のエンティティクラスまたはエンティティクラスのスーパークラス用に、新しいCriteriaインスタンスを作成します。

6

Criteria createCriteria(String entityName)

指定されたエンティティ名に対して、新しいCriteriaインスタンスを作成します。

7

Serializable getIdentifier(Object object)

このセッションに関連付けられている特定のエンティティの識別子値を返します。

8

Query createFilter(Object collection, String queryString)

指定されたコレクションとフィルター文字列に対してQueryの新しいインスタンスを作成します。

9

Query createQuery(String queryString)

指定されたHQLクエリ文字列に対してQueryの新しいインスタンスを作成します。

10

SQLQuery createSQLQuery(String queryString)

指定されたSQLクエリ文字列に対してSQLQueryの新しいインスタンスを作成します。

11

void delete(Object object)

データストアから永続インスタンスを削除します。

12

void delete(String entityName, Object object)

データストアから永続インスタンスを削除します。

13

Session get(String entityName, Serializable id)

指定された識別子を持つ指定された名前付きエンティティの永続インスタンスを返します。そのような永続インスタンスがない場合はnullを返します。

14

SessionFactory getSessionFactory()

このセッションを作成したセッションファクトリを取得します。

15

void refresh(Object object)

基盤となるデータベースから特定のインスタンスの状態を再読み取りします。

16

Transaction getTransaction()

このセッションに関連付けられたトランザクションインスタンスを取得します。

17

boolean isConnected()

セッションが現在接続されているかどうかを確認します。

18

boolean isDirty()

このセッションには、データベースと同期する必要がある変更が含まれていますか?

19

boolean isOpen()

セッションがまだ開いているかどうかを確認します。

20

Serializable save(Object object)

最初に生成された識別子を割り当てて、指定された一時インスタンスを永続化します。

21

void saveOrUpdate(Object object)

指定されたインスタンスをsave(Object)またはupdate(Object)します。

22

void update(Object object)

指定された分離インスタンスの識別子で永続インスタンスを更新します。

23

void update(String entityName, Object object)

指定された分離インスタンスの識別子で永続インスタンスを更新します。

Hibernate-永続クラス

Hibernateの全体的な概念は、Javaクラスの属性から値を取得し、それらをデータベーステーブルに保持することです。 マッピングドキュメントは、Hibernateがクラスから値を取得し、それらをテーブルおよび関連フィールドにマップする方法を決定するのに役立ちます。

オブジェクトまたはインスタンスがデータベーステーブルに格納されるJavaクラスは、Hibernateでは永続クラスと呼ばれます。 Hibernateは、これらのクラスが Plain Old Java Object (POJO)プログラミングモデルとも呼ばれるいくつかの単純なルールに従う場合に最適に機能します。

永続クラスの主なルールは次のとおりですが、これらのルールはどれも厳しい要件ではありません-

  • 永続化されるすべてのJavaクラスには、デフォルトのコンストラクターが必要です。
  • Hibernateおよびデータベース内のオブジェクトを簡単に識別できるように、すべてのクラスにIDを含める必要があります。 このプロパティは、データベーステーブルのプライマリキー列にマップします。
  • 永続化されるすべての属性はプライベートとして宣言され、 getXXX および setXXX メソッドがJavaBeanスタイルで定義されている必要があります。
  • Hibernateの中心的な機能であるプロキシは、永続クラスが最終でないか、すべてのパブリックメソッドを宣言するインターフェイスの実装に依存します。
  • EJBフレームワークに必要ないくつかの特殊なクラスとインターフェースを拡張または実装しないすべてのクラス。

POJO名は、特定のオブジェクトが特別なオブジェクトではなく、特にエンタープライズJavaBeanではない通常のJavaオブジェクトであることを強調するために使用されます。

簡単なPOJOの例

上記のいくつかのルールに基づいて、次のように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;
   }
}

Hibernate-マッピングファイル

通常、オブジェクト/リレーショナルマッピングはXMLドキュメントで定義されます。 このマッピングファイルはHibernateに指示します—定義されたクラスをデータベーステーブルにマップする方法は?

多くのHibernateユーザーは手作業でXMLを記述することを選択しますが、マッピングドキュメントを生成するためのツールがいくつか存在します。 これらには、上級Hibernateユーザー向けの XDoclet、Middlegen および AndroMDA が含まれます。

オブジェクトが次のセクションで定義されるテーブルに保持される、以前に定義された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;
   }
}

永続性を提供する各オブジェクトに対応するテーブルが1つあります。 上記のオブジェクトは、次のRDBMSテーブルに格納および取得する必要があることを考慮してください-

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

上記の2つのエンティティに基づいて、以下のマッピングファイルを定義できます。このファイルは、定義済みのクラスをデータベーステーブルにマッピングする方法をHibernateに指示します。

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

マッピングドキュメントは、<classname> .hbm.xml形式のファイルに保存する必要があります。 マッピング文書をファイルEmployee.hbm.xmlに保存しました。

マッピングファイルで使用されるマッピング要素について少し詳しく理解してみましょう-

  • マッピングドキュメントは、ルート要素として <hibernate-mapping> を持つXMLドキュメントであり、すべての <class> 要素が含まれます。
  • <class> 要素は、Javaクラスからデータベーステーブルへの特定のマッピングを定義するために使用されます。 Javaクラス名は、クラス要素の name 属性を使用して指定され、データベースの table 名は、table属性を使用して指定されます。
  • <meta> 要素はオプションの要素であり、クラスの説明を作成するために使用できます。
  • <id> 要素は、クラスの一意のID属性をデータベーステーブルの主キーにマップします。 id要素の name 属性はクラスのプロパティを参照し、 column 属性はデータベーステーブルの列を参照します。 type 属性はhibernateマッピングタイプを保持します。このマッピングタイプはJavaからSQLデータタイプに変換します。
  • id要素内の <generator> 要素は、主キー値を自動的に生成するために使用されます。 ジェネレーター要素の class 属性は native に設定され、休止状態が基になるデータベースの機能に応じて主キーを作成するために identity、sequence 、または hilo アルゴリズムを選択できるようにします。
  • <property> 要素は、Javaクラスプロパティをデータベーステーブルの列にマップするために使用されます。 要素の name 属性はクラスのプロパティを参照し、 column 属性はデータベーステーブルの列を参照します。 type 属性はhibernateマッピングタイプを保持します。このマッピングタイプはJavaからSQLデータタイプに変換します。

マッピングドキュメントで使用される他の属性と要素があります。Hibernateに関連する他のトピックについて議論しながら、できるだけ多くをカバーするようにします。

Hibernate-マッピングタイプ

Hibernateマッピングドキュメントを準備すると、Javaデータ型をRDBMSデータ型にマップすることがわかります。 マッピングファイルで宣言および使用される types はJavaデータ型ではありません。 SQLデータベースタイプでもありません。 これらのタイプは* Hibernateマッピングタイプ*と呼ばれ、JavaからSQLデータタイプへ、またはその逆に変換できます。

この章では、すべての基本、日付と時刻、ラージオブジェクト、およびその他のさまざまな組み込みマッピングタイプをリストします。

プリミティブ型

Mapping type Java type ANSI SQL Type
integer int or java.lang.Integer INTEGER
long long or java.lang.Long BIGINT
short short or java.lang.Short SMALLINT
float float or java.lang.Float FLOAT
double double or java.lang.Double DOUBLE
big_decimal java.math.BigDecimal NUMERIC
character java.lang.String CHAR(1)
string java.lang.String VARCHAR
byte byte or java.lang.Byte TINYINT
boolean boolean or java.lang.Boolean BIT
yes/no boolean or java.lang.Boolean CHAR(1) ('Y' or 'N')
true/false boolean or java.lang.Boolean CHAR(1) ('T' or 'F')

日付と時刻のタイプ

Mapping type Java type ANSI SQL Type
date java.util.Date or java.sql.Date DATE
time java.util.Date or java.sql.Time TIME
timestamp java.util.Date or java.sql.Timestamp TIMESTAMP
calendar java.util.Calendar TIMESTAMP
calendar_date java.util.Calendar DATE

バイナリおよびラージオブジェクトタイプ

Mapping type Java type ANSI SQL Type
binary byte[] VARBINARY (or BLOB)
text java.lang.String CLOB
serializable any Java class that implements java.io.Serializable VARBINARY (or BLOB)
clob java.sql.Clob CLOB
blob java.sql.Blob BLOB

JDK関連のタイプ

Mapping type Java type ANSI SQL Type
class java.lang.Class VARCHAR
locale java.util.Locale VARCHAR
timezone java.util.TimeZone VARCHAR
currency java.util.Currency VARCHAR

Hibernate-例

次に、Hibernateを使用してスタンドアロンアプリケーションでJava永続性を提供する方法を理解するための例を取り上げます。 Hibernateテクノロジーを使用してJavaアプリケーションを作成する際のさまざまな手順を説明します。

POJOクラスを作成する

アプリケーションを作成する最初のステップは、データベースに永続化されるアプリケーションに応じて、Java POJOクラスを作成することです。 getXXX および setXXX メソッドを持つ Employee クラスを考慮して、JavaBeans準拠のクラスにします。

POJO(Plain Old Java Object)は、EJBフレームワークがそれぞれ必要とするいくつかの特殊なクラスとインターフェースを拡張または実装しないJavaオブジェクトです。 通常のJavaオブジェクトはすべてPOJOです。

Hibernateによって永続化されるクラスを設計する場合、JavaBeans準拠のコードと、Employeeクラスの id 属性のようなインデックスとして機能する1つの属性を提供することが重要です。

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

データベーステーブルを作成する

2番目のステップは、データベースにテーブルを作成することです。 各オブジェクトに対応するテーブルが1つあり、永続性を提供します。 上記のオブジェクトは、次のRDBMSテーブルに格納および取得する必要があることを考慮してください-

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

マッピング構成ファイルの作成

この手順では、定義済みのクラスをデータベーステーブルにマップする方法をHibernateに指示するマッピングファイルを作成します。

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

マッピングドキュメントは、<classname> .hbm.xml形式のファイルに保存する必要があります。 マッピング文書をファイルEmployee.hbm.xmlに保存しました。 マッピングドキュメントに関する詳細を少し見てみましょう-

  • マッピングドキュメントは、すべての<class>要素を含むルート要素として<hibernate-mapping>を持つXMLドキュメントです。
  • <class> 要素は、Javaクラスからデータベーステーブルへの特定のマッピングを定義するために使用されます。 Javaクラス名はクラス要素の name 属性を使用して指定され、データベーステーブル名は table 属性を使用して指定されます。
  • <meta> 要素はオプションの要素であり、クラスの説明を作成するために使用できます。
  • <id> 要素は、クラスの一意のID属性をデータベーステーブルの主キーにマップします。 id要素の name 属性はクラスのプロパティを参照し、 column 属性はデータベーステーブルの列を参照します。 type 属性はhibernateマッピングタイプを保持します。このマッピングタイプはJavaからSQLデータタイプに変換します。
  • id要素内の <generator> 要素は、主キー値を自動的に生成するために使用されます。 ジェネレーター要素の class 属性は native に設定され、休止状態が基になるデータベースの機能に応じて主キーを作成するために identity、sequence または hilo アルゴリズムを選択できるようにします。
  • <property> 要素は、Javaクラスプロパティをデータベーステーブルの列にマップするために使用されます。 要素の name 属性はクラスのプロパティを参照し、 column 属性はデータベーステーブルの列を参照します。 type 属性はhibernateマッピングタイプを保持します。このマッピングタイプはJavaからSQLデータタイプに変換します。

マッピングドキュメントで使用される他の属性と要素があります。Hibernateに関連する他のトピックについて議論しながら、できるだけ多くをカバーするようにします。

アプリケーションクラスを作成する

最後に、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.SessionFactory;
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", 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(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*/
   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();
      }
   }
}

コンパイルと実行

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

  • 構成の章で説明されているように、hibernate.cfg.xml構成ファイルを作成します。
  • 上記のように、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-O/Rマッピング

これまで、Hibernateを使用した非常に基本的なO/Rマッピングを見てきましたが、3つの最も重要なマッピングトピックがあり、詳細に学習する必要があります。

これらは-

  • コレクションのマッピング、
  • エンティティクラス間の関連付けのマッピング、および
  • コンポーネントマッピング。

コレクションのマッピング

エンティティまたはクラスに特定の変数の値のコレクションがある場合、Javaで利用可能なコレクションインターフェイスのいずれかを使用してそれらの値をマップできます。 Hibernateは、 java.util.Map、java.util.Set、java.util.SortedMap、java.util.SortedSet、java.util.List 、および永続エンティティまたは値の array のインスタンスを永続化できます。

Sr.No. Collection type & Mapping Description
1

java.util.Set

これは<set>要素でマップされ、java.util.HashSetで初期化されます

2

java.util.SortedSet

これは<set>要素でマップされ、java.util.TreeSetで初期化されます。 sort 属性は、コンパレーターまたは自然順序付けのいずれかに設定できます。

3

java.util.List

これは<list>要素でマップされ、java.util.ArrayListで初期化されます

4

java.util.Collection

これは<bag>または<ibag>要素でマップされ、java.util.ArrayListで初期化されます

5

java.util.Map

これは<map>要素でマップされ、java.util.HashMapで初期化されます

6

java.util.SortedMap

これは<map>要素でマップされ、java.util.TreeMapで初期化されます。 sort 属性は、コンパレーターまたは自然順序付けのいずれかに設定できます。

Javaプリミティブ値タイプの場合は<primitive-array>、その他の場合は<array>を使用して、Hibernateは配列をサポートします。 ただし、これらはほとんど使用されないため、このチュートリアルでは説明しません。

Hibernateで直接サポートされていないユーザー定義のコレクションインターフェイスをマップする場合は、カスタムコレクションのセマンティクスについてHibernateに伝える必要がありますが、これは非常に簡単ではなく、使用することはお勧めしません。

関連付けマッピング

エンティティクラス間の関連付けとテーブル間の関係のマッピングは、ORMの魂です。 以下は、オブジェクト間の関係のカーディナリティを表現できる4つの方法です。 アソシエーションマッピングは、双方向だけでなく単方向にもできます。

Sr.No. Mapping type & Description
1

Many-to-One

Hibernateを使用した多対1の関係のマッピング

2

One-to-One

Hibernateを使用した1対1の関係のマッピング

3

One-to-Many

Hibernateを使用した1対多の関係のマッピング

4

Many-to-Many

Hibernateを使用した多対多の関係のマッピング

コンポーネントマッピング

Entityクラスは、メンバー変数として別のクラスへの参照を持つことができます。 参照されるクラスに独自のライフサイクルがなく、所有するエンティティクラスのライフサイクルに完全に依存する場合、参照されるクラスはしたがって*コンポーネントクラス*と呼ばれます。

コンポーネントのコレクションのマッピングも、わずかな設定の違いがある通常のコレクションのマッピングと同様の方法で可能です。 これらの2つのマッピングを例とともに詳しく見ていきます。

Sr.No. Mapping type & Description
1

Component Mappings

メンバー変数として別のクラスへの参照を持つクラスのマッピング。

Hibernate-アノテーション

これまで、HibernateがPOJOからデータベーステーブルへ、またはその逆にデータを変換するためにXMLマッピングファイルを使用する方法を見てきました。 Hibernateアノテーションは、XMLファイルを使用せずにマッピングを定義する最新の方法です。 XMLマッピングメタデータに加えて、またはXMLマッピングメタデータの代替として注釈を使用できます。

Hibernate Annotationsは、オブジェクトとリレーショナルテーブルのマッピングにメタデータを提供する強力な方法です。 すべてのメタデータはコードとともにPOJO javaファイルに組み込まれます。これにより、ユーザーは開発中にテーブル構造とPOJOを同時に理解できます。

アプリケーションを他のEJB 3準拠のORMアプリケーションに移植できるようにする場合は、アノテーションを使用してマッピング情報を表す必要がありますが、それでも柔軟性が必要な場合は、XMLベースのマッピングを使用する必要があります。

Hibernate Annotationの環境設定

まず、JDK 5.0を使用していることを確認する必要があります。そうでない場合は、アノテーションのネイティブサポートを利用するためにJDKをJDK 5.0にアップグレードする必要があります。

次に、sourceforgeから入手できるHibernate 3.xアノテーション配布パッケージをインストールする必要があります:(https://sourceforge.net/projects/hibernate/files/hibernate-annotations/[Hibernate Annotationのダウンロード])および hibernateをコピーします-annotations.jar、lib/hibernate-comons-annotations.jar 、およびHibernate AnnotationsディストリビューションからCLASSPATHへの lib/ejb3-persistence.jar

注釈付きクラスの例

Hibernate Annotationでの作業中に前述したように、すべてのメタデータはコードとともに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アノテーションを配置した場合、デフォルトでgetterおよびsetterメソッドを介してプロパティにアクセスできるようになります。 したがって、他のすべての注釈も、選択された戦略に従って、フィールドまたはゲッターメソッドに配置されます。

次のセクションでは、上記のクラスで使用される注釈について説明します。

@Entityアノテーション

EJB 3標準注釈は javax.persistence パッケージに含まれているため、最初のステップとしてこのパッケージをインポートします。 次に、Employeeクラスに @ Entity アノテーションを使用しました。これは、このクラスをエンティティBeanとしてマークするため、少なくとも保護されたスコープで表示される引数なしのコンストラクタが必要です。

@Tableアノテーション

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

@Tableアノテーションは4つの属性を提供します。これにより、テーブルの名前、カタログ、およびスキーマをオーバーライドし、テーブルの列に一意の制約を適用できます。 今のところ、テーブル名、つまりEMPLOYEEのみを使用しています。

@Idおよび@GeneratedValueアノテーション

各エンティティBeanには主キーがあり、クラスに @ Id アノテーションを付けます。 主キーは、テーブル構造に応じて単一のフィールドまたは複数のフィールドの組み合わせにすることができます。

デフォルトでは、@ Idアノテーションは使用する最も適切な主キー生成戦略を自動的に決定しますが、 @ GeneratedValue アノテーションを適用することでこれをオーバーライドできます。ここで説明するので、デフォルトのキー生成戦略のみを使用しましょう。 使用するジェネレータータイプを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-クエリ言語

Hibernate Query Language(HQL)はSQLに似たオブジェクト指向のクエリ言語ですが、HQLはテーブルと列を操作する代わりに、永続オブジェクトとそのプロパティを操作します。 HQLクエリは、Hibernateによって従来のSQLクエリに変換され、データベースでアクションを実行します。

ネイティブSQLを使用してSQLステートメントをHibernateで直接使用できますが、データベースの移植性の面倒を避け、HibernateのSQL生成およびキャッシュ戦略を活用するために、可能な限りHQLを使用することをお勧めします。

SELECT、FROM、WHEREなどのキーワードでは大文字と小文字は区別されませんが、HQLではテーブル名や列名などのプロパティでは大文字と小文字が区別されます。

FROM句

完全な永続オブジェクトをメモリにロードする場合は、 FROM 句を使用します。 以下は、FROM句を使用する簡単な構文です-

String hql = "FROM Employee";
Query query = session.createQuery(hql);
List results = query.list();

HQLでクラス名を完全に修飾する必要がある場合は、次のようにパッケージとクラス名を指定するだけです-

String hql = "FROM com.hibernatebook.criteria.Employee";
Query query = session.createQuery(hql);
List results = query.list();

AS句

特に長いクエリがある場合、 AS 句を使用して、HQLクエリのクラスにエイリアスを割り当てることができます。 たとえば、前の単純な例は次のようになります-

String hql = "FROM Employee AS E";
Query query = session.createQuery(hql);
List results = query.list();
*AS* キーワードはオプションであり、次のようにクラス名の直後にエイリアスを指定することもできます-
String hql = "FROM Employee E";
Query query = session.createQuery(hql);
List results = query.list();

SELECT句

*SELECT* 句を使用すると、from句よりも結果セットをより詳細に制御できます。 オブジェクト全体ではなくオブジェクトのプロパティをほとんど取得しない場合は、SELECT句を使用します。 以下は、SELECT句を使用してEmployeeオブジェクトのfirst_nameフィールドのみを取得する簡単な構文です-
String hql = "SELECT E.firstName FROM Employee E";
Query query = session.createQuery(hql);
List results = query.list();

ここで注目すべきは、 Employee.firstName がEMPLOYEEテーブルのフィールドではなく、Employeeオブジェクトのプロパティであることです。

WHERE句

ストレージから返される特定のオブジェクトを絞り込む場合は、WHERE句を使用します。 以下は、WHERE句を使用する簡単な構文です-

String hql = "FROM Employee E WHERE E.id = 10";
Query query = session.createQuery(hql);
List results = query.list();

ORDER BY句

HQLクエリの結果を並べ替えるには、 ORDER BY 句を使用する必要があります。 結果セット内のオブジェクトのプロパティごとに、昇順(ASC)または降順(DESC)で結果を並べ替えることができます。 以下は、ORDER BY句を使用する簡単な構文です-

String hql = "FROM Employee E WHERE E.id > 10 ORDER BY E.salary DESC";
Query query = session.createQuery(hql);
List results = query.list();

あなたが複数のプロパティでソートしたい場合は、次のようにコンマで区切られた追加のプロパティをorder by句の最後に追加するだけです-

String hql = "FROM Employee E WHERE E.id > 10 " +
             "ORDER BY E.firstName DESC, E.salary DESC ";
Query query = session.createQuery(hql);
List results = query.list();

GROUP BY句

この句により、Hibernateはデータベースから情報を取得し、属性の値に基づいてグループ化し、通常は結果を使用して集計値を含めます。 GROUP BY句を使用する簡単な構文は次のとおりです-

String hql = "SELECT SUM(E.salary), E.firtName FROM Employee E " +
             "GROUP BY E.firstName";
Query query = session.createQuery(hql);
List results = query.list();

名前付きパラメーターの使用

Hibernateは、HQLクエリで名前付きパラメーターをサポートします。 これにより、ユーザーからの入力を受け入れるHQLクエリを簡単に作成でき、SQLインジェクション攻撃から保護する必要はありません。 以下は、名前付きパラメータを使用する簡単な構文です-

String hql = "FROM Employee E WHERE E.id = :employee_id";
Query query = session.createQuery(hql);
query.setParameter("employee_id",10);
List results = query.list();

UPDATE句

一括更新は、Hibernate 3でのHQLの新機能であり、Hibernate 3での削除作業はHibernate 2での削除作業とは異なります。 Queryインターフェースには、HQL UPDATEまたはDELETEステートメントを実行するためのexecuteUpdate()というメソッドが含まれています。

*UPDATE* 句を使用して、1つ以上のオブジェクトの1つ以上のプロパティを更新できます。 以下は、UPDATE句を使用する簡単な構文です-
String hql = "UPDATE Employee set salary = :salary "  +
             "WHERE id = :employee_id";
Query query = session.createQuery(hql);
query.setParameter("salary", 1000);
query.setParameter("employee_id", 10);
int result = query.executeUpdate();
System.out.println("Rows affected: " + result);

DELETE句

*DELETE* 句を使用して、1つ以上のオブジェクトを削除できます。 以下は、DELETE句を使用する簡単な構文です-
String hql = "DELETE FROM Employee "  +
             "WHERE id = :employee_id";
Query query = session.createQuery(hql);
query.setParameter("employee_id", 10);
int result = query.executeUpdate();
System.out.println("Rows affected: " + result);

INSERT句

HQLは、あるオブジェクトから別のオブジェクトにレコードを挿入できる場合にのみ、 INSERT INTO 句をサポートします。 以下は、INSERT INTO句を使用する単純な構文です-

String hql = "INSERT INTO Employee(firstName, lastName, salary)"  +
             "SELECT firstName, lastName, salary FROM old_employee";
Query query = session.createQuery(hql);
int result = query.executeUpdate();
System.out.println("Rows affected: " + result);

集計メソッド

HQLは、SQLと同様に、さまざまな集計メソッドをサポートしています。 それらはSQLと同じようにHQLで機能し、以下は利用可能な関数のリストです-

Sr.No. Functions & Description
1

avg(property name)

プロパティの値の平均

2

count(property name or *)

結果でプロパティが発生する回数

3

max(property name)

プロパティ値の最大値

4

min(property name)

プロパティ値の最小値

5

sum(property name)

プロパティ値の合計

*distinct* キーワードは、行セット内の一意の値のみをカウントします。 次のクエリは一意のカウントのみを返します-
String hql = "SELECT count(distinct E.firstName) FROM Employee E";
Query query = session.createQuery(hql);
List results = query.list();

クエリを使用したページネーション

ページ付けのためのQueryインターフェースには2つのメソッドがあります。

Sr.No. Method & Description
1

Query setFirstResult(int startPosition)

このメソッドは、結果セットの行0から始まる最初の行を表す整数を受け取ります。

2

Query setMaxResults(int maxResult)

このメソッドは、オブジェクトの固定数 maxResults を取得するようにHibernateに指示します。

上記の2つの方法を一緒に使用して、WebアプリケーションまたはSwingアプリケーションでページングコンポーネントを構築できます。 以下は、一度に10行をフェッチするように拡張できる例です-

String hql = "FROM Employee";
Query query = session.createQuery(hql);
query.setFirstResult(1);
query.setMaxResults(10);
List results = query.list();

Hibernate-基準クエリ

Hibernateは、RDBMSテーブルで利用可能なオブジェクトとデータを操作する別の方法を提供します。 メソッドの1つにCriteria APIがあります。このAPIを使用すると、フィルタールールと論理条件を適用できるプログラムで条件クエリオブジェクトを構築できます。

Hibernate Session インターフェースは* createCriteria()メソッドを提供します。このメソッドを使用して、アプリケーションが条件クエリを実行するときに永続化オブジェクトのクラスのインスタンスを返す *Criteria オブジェクトを作成できます。

次に、条件クエリの最も単純な例を示します。これは、Employeeクラスに対応するすべてのオブジェクトを返すだけです。

Criteria cr = session.createCriteria(Employee.class);
List results = cr.list();

基準の制限

*Criteria* オブジェクトで使用可能な* add()*メソッドを使用して、条件クエリの制限を追加できます。 以下は、給与が2000に等しいレコードを返すための制限を追加する例です-
Criteria cr = session.createCriteria(Employee.class);
cr.add(Restrictions.eq("salary", 2000));
List results = cr.list();

以下は、さまざまなシナリオをカバーするいくつかの例であり、要件に従って使用できます-

Criteria cr = session.createCriteria(Employee.class);

//To get records having salary more than 2000
cr.add(Restrictions.gt("salary", 2000));

//To get records having salary less than 2000
cr.add(Restrictions.lt("salary", 2000));

//To get records having fistName starting with zara
cr.add(Restrictions.like("firstName", "zara%"));

//Case sensitive form of the above restriction.
cr.add(Restrictions.ilike("firstName", "zara%"));

//To get records having salary in between 1000 and 2000
cr.add(Restrictions.between("salary", 1000, 2000));

//To check if the given property is null
cr.add(Restrictions.isNull("salary"));

//To check if the given property is not null
cr.add(Restrictions.isNotNull("salary"));

//To check if the given property is empty
cr.add(Restrictions.isEmpty("salary"));

//To check if the given property is not empty
cr.add(Restrictions.isNotEmpty("salary"));

次のようにLogicalExpression制限を使用してANDまたはOR条件を作成できます-

Criteria cr = session.createCriteria(Employee.class);

Criterion salary = Restrictions.gt("salary", 2000);
Criterion name = Restrictions.ilike("firstNname","zara%");

//To get records matching with OR conditions
LogicalExpression orExp = Restrictions.or(salary, name);
cr.add( orExp );

//To get records matching with AND conditions
LogicalExpression andExp = Restrictions.and(salary, name);
cr.add( andExp );

List results = cr.list();

前のチュートリアルで説明したように、上記のすべての条件はHQLで直接使用できます。

基準を使用したページネーション

ページネーションのためのCriteriaインターフェースには2つの方法があります。

Sr.No. Method & Description
1

public Criteria setFirstResult(int firstResult)

このメソッドは、結果セットの行0から始まる最初の行を表す整数を受け取ります。

2

public Criteria setMaxResults(int maxResults)

このメソッドは、オブジェクトの固定数 maxResults を取得するようにHibernateに指示します。

上記の2つの方法を一緒に使用して、WebアプリケーションまたはSwingアプリケーションでページングコンポーネントを構築できます。 以下は、一度に10行をフェッチするように拡張できる例です-

Criteria cr = session.createCriteria(Employee.class);
cr.setFirstResult(1);
cr.setMaxResults(10);
List results = cr.list();

結果の並べ替え

Criteria APIは org.hibernate.criterion.Order クラスを提供し、オブジェクトのプロパティの1つに従って、結果セットを昇順または降順でソートします。 この例では、Orderクラスを使用して結果セットを並べ替える方法を示します-

Criteria cr = session.createCriteria(Employee.class);

//To get records having salary more than 2000
cr.add(Restrictions.gt("salary", 2000));

//To sort records in descening order
cr.addOrder(Order.desc("salary"));

//To sort records in ascending order
cr.addOrder(Order.asc("salary"));

List results = cr.list();

予測と集計

Criteria APIは org.hibernate.criterion.Projections クラスを提供します。これを使用して、プロパティ値の平均、最大、または最小を取得できます。 Projectionsクラスは、 Projection インスタンスを取得するためのいくつかの静的ファクトリメソッドを提供するという点で、Restrictionsクラスに似ています。

以下は、さまざまなシナリオをカバーするいくつかの例であり、要件ごとに使用できます-

Criteria cr = session.createCriteria(Employee.class);

//To get total row count.
cr.setProjection(Projections.rowCount());

//To get average of a property.
cr.setProjection(Projections.avg("salary"));

//To get distinct count of a property.
cr.setProjection(Projections.countDistinct("firstName"));

//To get maximum of a property.
cr.setProjection(Projections.max("salary"));

//To get minimum of a property.
cr.setProjection(Projections.min("salary"));

//To get sum of a property.
cr.setProjection(Projections.sum("salary"));

基準クエリの例

次の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()メソッドを使用してアプリケーションクラスを作成し、 Criteria クエリを使用するアプリケーションを実行します-

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.SessionFactory;
import org.hibernate.Criteria;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.Projections;
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 all the employees*/
      ME.listEmployees();

     /*Print Total employee's count*/
      ME.countEmployee();

     /*Print Total salary*/
      ME.totalSalary();
   }

  /*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 having salary more than 2000*/
   public void listEmployees( ) {
      Session session = factory.openSession();
      Transaction tx = null;

      try {
         tx = session.beginTransaction();
         Criteria cr = session.createCriteria(Employee.class);
        //Add restriction.
         cr.add(Restrictions.gt("salary", 2000));
         List employees = cr.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 print total number of records*/
   public void countEmployee(){
      Session session = factory.openSession();
      Transaction tx = null;

      try {
         tx = session.beginTransaction();
         Criteria cr = session.createCriteria(Employee.class);

        //To get total row count.
         cr.setProjection(Projections.rowCount());
         List rowCount = cr.list();

         System.out.println("Total Coint: " + rowCount.get(0) );
         tx.commit();
      } catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace();
      } finally {
         session.close();
      }
   }

  /*Method to print sum of salaries*/
   public void totalSalary(){
      Session session = factory.openSession();
      Transaction tx = null;

      try {
         tx = session.beginTransaction();
         Criteria cr = session.createCriteria(Employee.class);

        //To get total salary.
         cr.setProjection(Projections.sum("salary"));
         List totalSalary = cr.list();

         System.out.println("Total Salary: " + totalSalary.get(0) );
         tx.commit();
      } catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace();
      } finally {
         session.close();
      }
   }
}

コンパイルと実行

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

  • 構成の章で説明されているように、hibernate.cfg.xml構成ファイルを作成します。
  • 上記のように、Employee.hbm.xmlマッピングファイルを作成します。
  • 上記のようにEmployee.javaソースファイルを作成し、コンパイルします。
  • 上記のようにManageEmployee.javaソースファイルを作成し、コンパイルします。 *ManageEmployeeバイナリを実行してプログラムを実行します。

次の結果が得られ、EMPLOYEEテーブルにレコードが作成されます。

$java ManageEmployee
.......VARIOUS LOG MESSAGES WILL DISPLAY HERE........

First Name: Daisy  Last Name: Das  Salary: 5000
First Name: John  Last Name: Paul  Salary: 5000
First Name: Mohd  Last Name: Yasee  Salary: 3000
Total Coint: 4
Total Salary: 15000

EMPLOYEEテーブルを確認する場合、次のレコードが必要です。

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

Hibernate-ネイティブSQL

OracleのクエリヒントやCONNECTキーワードなどのデータベース固有の機能を利用する場合は、ネイティブSQLを使用してデータベースクエリを表現できます。 Hibernate 3.xでは、すべての作成、更新、削除、および読み込み操作に対して、ストアドプロシージャを含む手書きのSQLを指定できます。

アプリケーションは、セッションインターフェイスの* createSQLQuery()*メソッドを使用して、セッションからネイティブSQLクエリを作成します-

public SQLQuery createSQLQuery(String sqlString) throws HibernateException

SQLクエリを含む文字列をcreateSQLQuery()メソッドに渡した後、addEntity()、addJoin()、addScalar()メソッドを使用して、SQL結果を既存のHibernateエンティティ、結合、またはスカラー結果のいずれかに関連付けることができます。それぞれ。

スカラークエリ

最も基本的なSQLクエリは、1つ以上のテーブルからスカラー(値)のリストを取得することです。 以下は、スカラー値にネイティブ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();

エンティティクエリ

上記のクエリはすべてスカラー値を返すことに関するもので、基本的には結果セットから「生の」値を返します。 以下は、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();

ネイティブ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()メソッドを使用してアプリケーションクラスを作成し、 Native 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を適切に設定してください。

  • 構成の章で説明されているように、hibernate.cfg.xml構成ファイルを作成します。
  • 上記のように、Employee.hbm.xmlマッピングファイルを作成します。
  • 上記のようにEmployee.javaソースファイルを作成し、コンパイルします。
  • 上記のようにManageEmployee.javaソースファイルを作成し、コンパイルします。 *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)
mysql>

休止状態-キャッシュ

キャッシングは、システムのパフォーマンスを向上させるメカニズムです。 これは、アプリケーションとデータベースの間にあるバッファメモリです。 キャッシュメモリは、データベースのヒット数を可能な限り減らすために、最近使用したデータ項目を保存します。

キャッシングはHibernateにとっても重要です。 以下で説明するように、マルチレベルキャッシングスキームを利用します-

Hibernate Caching

一次キャッシュ

1次キャッシュはセッションキャッシュであり、すべての要求が通過する必要がある必須キャッシュです。 Sessionオブジェクトは、データベースにコミットする前にオブジェクトを独自の力で保持します。

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

二次キャッシュ

2次キャッシュはオプションのキャッシュであり、1次キャッシュは、2次キャッシュ内のオブジェクトの検索を試みる前に常に参照されます。 2次キャッシュは、クラスごとおよびコレクションごとに構成でき、主にセッション全体のオブジェクトのキャッシュを担当します。

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

クエリレベルキャッシュ

Hibernateは、2次キャッシュと密接に統合するクエリ結果セットのキャッシュも実装します。

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

二次キャッシュ

Hibernateはデフォルトで一次キャッシュを使用しますが、一次キャッシュを使用しても何もする必要はありません。 オプションの2次キャッシュに直接進みましょう。 すべてのクラスがキャッシュの恩恵を受けるわけではないため、2次キャッシュを無効にできることが重要です。

Hibernate 2次キャッシュは2つのステップでセットアップされます。 最初に、使用する同時方式を決定する必要があります。 その後、キャッシュプロバイダーを使用して、キャッシュの有効期限と物理キャッシュ属性を構成します。

並行性戦略

並行性戦略はメディエーターであり、データ項目をキャッシュに保存し、キャッシュからそれらを取得します。 2次キャッシュを有効にする場合は、永続クラスとコレクションごとに、使用するキャッシュ同時方式を決定する必要があります。

  • トランザクション-更新のまれなケースで、同時トランザクションで古いデータを防ぐことが重要である場合、ほとんどのデータに対してこの戦略を使用します。

  • 読み取り/書き込み-更新のまれなケースで、同時トランザクションで古いデータを防止することが重要である場合、読み取り方式のデータに対して再びこの戦略を使用します。

  • Nonstrict-read-write -この戦略は、キャッシュとデータベース間の一貫性を保証しません。 データがほとんど変化せず、古いデータのわずかな可能性が重大な関心事ではない場合、この戦略を使用します。

  • 読み取り専用-データに適した並行性戦略であり、変更されることはありません。 参照データのみに使用します。

    *Employee* クラスに第2レベルのキャッシングを使用する場合、読み書き戦略を使用してEmployeeインスタンスをキャッシュするようHibernateに指示するために必要なマッピング要素を追加しましょう。
<?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では、アプリケーション全体に対して単一のキャッシュプロバイダーを選択する必要があります。

Sr.No. Cache Name & Description
1

EHCache

メモリまたはディスクおよびクラスターキャッシュにキャッシュでき、オプションのHibernateクエリ結果キャッシュをサポートします。

2

OSCache

有効な一連の有効期限ポリシーとクエリキャッシュのサポートにより、単一のJVMのメモリとディスクへのキャッシュをサポートします。

3

warmCache

JGroupsに基づくクラスターキャッシュ。 クラスター化された無効化を使用しますが、Hibernateクエリキャッシュはサポートしません。

4

JBoss Cache

JGroupsマルチキャストライブラリにも基づいた、完全にトランザクション化されたクラスター化キャッシュ。 レプリケーションまたは無効化、同期または非同期通信、および楽観的および悲観的ロックをサポートします。 Hibernateクエリキャッシュがサポートされています。

すべてのキャッシュプロバイダーは、すべての同時方式と互換性があるわけではありません。 次の互換性マトリックスは、適切な組み合わせの選択に役立ちます。

Strategy/Provider Read-only Nonstrictread-write Read-write Transactional
EHCache X X X  
OSCache X X X  
SwarmCache X X    
JBoss Cache X     X

hibernate.cfg.xml構成ファイルでキャッシュプロバイダーを指定します。 EHCacheを2次キャッシュプロバイダーとして選択します-

<?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にある必要があります。 Employeeクラスのehcache.xmlのキャッシュ構成は次のようになります-

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

これで、2番目のレベルのキャッシュがEmployeeクラスとHibernateで有効になり、Employeeに移動するとき、または識別子でEmployeeを読み込むたびに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-バッチ処理

Hibernateを使用してデータベースに大量のレコードをアップロードする必要がある場合を考えてください。 以下は、Hibernateを使用してこれを達成するためのコードスニペットです-

Session session = SessionFactory.openSession();
Transaction tx = session.beginTransaction();
for ( int i=0; i<100000; i++ ) {
   Employee employee = new Employee(.....);
   session.save(employee);
}
tx.commit();
session.close();

デフォルトでは、Hibernateはすべての永続オブジェクトをセッションレベルのキャッシュにキャッシュし、最終的にアプリケーションは50,000番目の行のどこかで OutOfMemoryException で倒れます。 Hibernateで*バッチ処理*を使用している場合、この問題を解決できます。

バッチ処理機能を使用するには、最初に hibernate.jdbc.batch_size をオブジェクトサイズに応じて20または50の数値にバッチサイズとして設定します。 これは、すべてのX行がバッチとして挿入されることを休止状態コンテナに伝えます。 これをコードに実装するには、次のように少し変更する必要があります-

Session session = SessionFactory.openSession();
Transaction tx = session.beginTransaction();
for ( int i=0; i<100000; i++ ) {
   Employee employee = new Employee(.....);
   session.save(employee);
   if( i % 50 == 0 ) {//Same as the JDBC batch size
     //flush a batch of inserts and release memory:
      session.flush();
      session.clear();
   }
}
tx.commit();
session.close();

上記のコードは、INSERT操作に対しては正常に機能しますが、UPDATE操作を実行する場合は、次のコードを使用して実現できます-

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();

ScrollableResults employeeCursor = session.createQuery("FROM EMPLOYEE").scroll();
int count = 0;

while ( employeeCursor.next() ) {
   Employee employee = (Employee) employeeCursor.get(0);
   employee.updateEmployee();
   seession.update(employee);
   if ( ++count % 50 == 0 ) {
      session.flush();
      session.clear();
   }
}
tx.commit();
session.close();

バッチ処理の例

構成ファイルを変更して、 hibernate.jdbc.batch_size プロパティを追加しましょう-

<?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.jdbc.batch_size">
         50
      </property>

      <!-- List of XML mapping files -->
      <mapping resource = "Employee.hbm.xml"/>

   </session-factory>
</hibernate-configuration>

次のPOJO Employeeクラスを考慮してください-

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

以下は、従業員オブジェクトを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>

      <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()メソッドを使用してアプリケーションクラスを作成し、Sessionオブジェクトで使用可能な* flush()および clear()*メソッドを使用するアプリケーションを実行して、Hibernateがこれらのレコードをデータベースに書き込み続けるようにしますそれらをメモリにキャッシュします。

import java.util.*;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
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 Configuration().configure().buildSessionFactory();
      } catch (Throwable ex) {
         System.err.println("Failed to create sessionFactory object." + ex);
         throw new ExceptionInInitializerError(ex);
      }
      ManageEmployee ME = new ManageEmployee();

     /*Add employee records in batches*/
      ME.addEmployees( );
   }

  /*Method to create employee records in batches*/
   public void addEmployees( ){
      Session session = factory.openSession();
      Transaction tx = null;
      Integer employeeID = null;

      try {
         tx = session.beginTransaction();
         for ( int i=0; i<100000; i++ ) {
            String fname = "First Name " + i;
            String lname = "Last Name " + i;
            Integer salary = i;
            Employee employee = new Employee(fname, lname, salary);
            session.save(employee);
            if( i % 50 == 0 ) {
               session.flush();
               session.clear();
            }
         }
         tx.commit();
      } catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace();
      } finally {
         session.close();
      }
      return ;
   }
}

コンパイルと実行

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

  • 上記の説明に従ってhibernate.cfg.xml構成ファイルを作成します。
  • 上記のように、Employee.hbm.xmlマッピングファイルを作成します。
  • 上記のようにEmployee.javaソースファイルを作成し、コンパイルします。
  • 上記のようにManageEmployee.javaソースファイルを作成し、コンパイルします。
  • ManageEmployeeバイナリを実行してプログラムを実行すると、EMPLOYEEテーブルに100000レコードが作成されます。

Hibernate-インターセプター

Hibernateで学習したように、オブジェクトが作成され、永続化されます。 オブジェクトを変更したら、データベースに保存する必要があります。 このプロセスは、オブジェクトが次に必要になるまで続き、永続ストアからロードされます。

したがって、オブジェクトはライフサイクルのさまざまな段階を通過し、 Interceptor Interface はメソッドを提供します。これらのメソッドはさまざまな段階で呼び出して、いくつかの必要なタスクを実行できます。 これらのメソッドは、セッションからアプリケーションへのコールバックであり、アプリケーションが保存、更新、削除、またはロードされる前に、永続オブジェクトのプロパティを検査および/または操作できるようにします。 以下は、Interceptorインターフェース内で使用可能なすべてのメソッドのリストです-

Sr.No. Method & Description
1

findDirty()

このメソッドは、Sessionオブジェクトで* flush()*メソッドが呼び出されたときに呼び出されます。

2

instantiate()

このメソッドは、永続化されたクラスがインスタンス化されるときに呼び出されます。

3

isUnsaved()

このメソッドは、オブジェクトが* saveOrUpdate()*メソッドに渡されたときに呼び出されます/

4

onDelete()

このメソッドは、オブジェクトが削除される前に呼び出されます。

5

onFlushDirty()

このメソッドは、オブジェクトがダーティであることをHibernateが検出したときに呼び出されます(つまり、 フラッシュ中に変更されました) 更新操作。

6

onLoad()

このメソッドは、オブジェクトが初期化される前に呼び出されます。

7

onSave()

このメソッドは、オブジェクトが保存される前に呼び出されます。

8

postFlush()

このメソッドは、フラッシュが発生し、メモリ内のオブジェクトが更新された後に呼び出されます。

9

preFlush()

このメソッドは、フラッシュの前に呼び出されます。

Hibernate Interceptorは、アプリケーションとデータベースの両方に対してオブジェクトがどのように見えるかを完全に制御します。

インターセプターの使用方法

インターセプターを作成するには、 Interceptor クラスを直接実装するか、 EmptyInterceptor クラスを拡張します。 以下は、Hibernate Interceptor機能を使用する簡単な手順です。

インターセプターを作成する

この例では、 Employee オブジェクトが作成および更新されたときにInterceptorのメソッドが自動的に呼び出されるEmptyInterceptorを拡張します。 要件に応じてより多くのメソッドを実装できます。

import java.io.Serializable;
import java.util.Date;
import java.util.Iterator;

import org.hibernate.EmptyInterceptor;
import org.hibernate.Transaction;
import org.hibernate.type.Type;

public class MyInterceptor extends EmptyInterceptor {
   private int updates;
   private int creates;
   private int loads;

   public void onDelete(Object entity, Serializable id,
      Object[] state, String[] propertyNames, Type[] types) {
      //do nothing
   }

  //This method is called when Employee object gets updated.
   public boolean onFlushDirty(Object entity, Serializable id,
      Object[] currentState, Object[] previousState, String[] propertyNames,
      Type[] types) {
         if ( entity instanceof Employee ) {
            System.out.println("Update Operation");
            return true;
         }
         return false;
   }

   public boolean onLoad(Object entity, Serializable id,
      Object[] state, String[] propertyNames, Type[] types) {
        //do nothing
         return true;
   }

  //This method is called when Employee object gets created.
   public boolean onSave(Object entity, Serializable id,
      Object[] state, String[] propertyNames, Type[] types) {
         if ( entity instanceof Employee ) {
            System.out.println("Create Operation");
            return true;
         }
         return false;
   }

  //called before commit into database
   public void preFlush(Iterator iterator) {
      System.out.println("preFlush");
   }

  //called after committed into database
   public void postFlush(Iterator iterator) {
      System.out.println("postFlush");
   }
}

POJOクラスを作成する

さて、EMPLOYEEテーブルとEmployeeクラスを使用して遊んだ最初の例を少し変更しましょう-

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

データベーステーブルを作成する

2番目のステップは、データベースにテーブルを作成することです。 各オブジェクトに対応するテーブルが1つあり、永続性を提供します。 上記のオブジェクトを考慮し、次のRDBMSテーブルに格納および取得する必要があります-

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

マッピング構成ファイルの作成

この手順では、Hibernateに指示するマッピングファイルを作成します。定義されたクラスをデータベーステーブルにマップする方法です。

<?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()メソッドを使用してアプリケーションクラスを作成し、アプリケーションを実行します。 ここで、セッションオブジェクトの作成中に、Interceptorクラスを引数として使用したことに注意してください。

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.SessionFactory;
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", 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( new MyInterceptor() );
      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*/
   public void listEmployees( ){
      Session session = factory.openSession( new MyInterceptor() );
      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( new MyInterceptor() );
      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( new MyInterceptor() );
      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();
      }
   }
}

コンパイルと実行

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

  • 構成の章で説明されているように、hibernate.cfg.xml構成ファイルを作成します。
  • 上記のように、Employee.hbm.xmlマッピングファイルを作成します。
  • 上記のようにEmployee.javaソースファイルを作成し、コンパイルします。
  • 上記のようにMyInterceptor.javaソースファイルを作成し、コンパイルします。
  • 上記のようにManageEmployee.javaソースファイルを作成し、コンパイルします。 *ManageEmployeeバイナリを実行してプログラムを実行します。

次の結果が得られ、EMPLOYEEテーブルにレコードが作成されます。

$java ManageEmployee
.......VARIOUS LOG MESSAGES WILL DISPLAY HERE........

Create Operation
preFlush
postFlush
Create Operation
preFlush
postFlush
Create Operation
preFlush
postFlush
First Name: Zara  Last Name: Ali  Salary: 1000
First Name: Daisy  Last Name: Das  Salary: 5000
First Name: John  Last Name: Paul  Salary: 10000
preFlush
postFlush
preFlush
Update Operation
postFlush
preFlush
postFlush
First Name: Zara  Last Name: Ali  Salary: 5000
First Name: John  Last Name: Paul  Salary: 10000
preFlush
postFlush

あなたの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-questions-answers