JPA (Java Persistence API)

JPA(Java Persistence API)とは、リレーショナルデータベースのO/Rマッピングを行うためのフレームワークです。JPA仕様を実装したものとして、Spring Data JPAやHibernateなどが挙げられる。

  1. 1 アノテーション
    1. 1.1 @Column
    2. 1.2 @Entity
    3. 1.3 @GeneratedValue
    4. 1.4 @Id
    5. 1.5 @Table
  2. 2 例外
    1. 2.1 EntityExistsExeption

JPA概要

JPA (Java Persistence API)は、O/Rマッピング・アーキテクチャのJava用フレームワークである。Javaオブジェクトをデータベースに格納したり、データベースのデータをJavaオブジェクトに変換する処理を自動化したりするため、JDBCを直接使用するのに比べ、簡素なプログラムコードでデータベース処理を実現できる。

JDBCを直接使用するアプリケーションは、製品固有のSQLに依存したコードがネックとなり、その移植性を阻害していたが、JPAは製品間の違いを多く吸収するため高い移植性を保つことができる。

JPAでは、Javaオブジェクトとデータベースのテーブル間のマッピング情報を、アノテーションを用いて定義する。これにより、エンティティをPOJO (Plain Old Java Object)で実装できたり、複雑な定義ファイルを作成する必要が無くなるなど、開発容易性を確保することができる。

JPA主要概念

エンティティ

エンティティとは、データベースのテーブルに関連付けるJavaBeansである。エンティティはPOJO (Plain Old Java Object)として実装し、データベーステーブルとの関連は、アノテーションを使って定義する。エンティティ操作のためのAPIは、エンティティマネージャが提供する。

エンティティマネージャ

エンティティマネージャは、アプリケーションに対してCRUD操作のためのインタフェースを提供する。また、永続化コンテキスト上のエンティティの状態管理と、エンティティとデータベース間の同期化を行う。

永続化コンテキスト

永続化コンテキストは、エンティティマネージャが管理する、メモリ上のエンティティの集合である。エンティティマネージャは、コンテキスト上のエンティティオブジェクトとライフサイクルを管理する。

エンティティマネージャファクトリ

エンティティマネージャファクトリは、エンティティマネージャを生成するファクトリの役割を果たす。

永続化ユニット

永続化ユニットは、エンティティマネージャ単位に用意する。永続化に関する構成情報(エンティティクラス、データソース等)を保持するリポジトリである。定義情報は、XMLファイル(persistence.xml)に定義する。

永続化プロバイダ

EJBコンテナ、またはアプリケーションから呼び出され、エンティティマネージャファクトリを生成する。JPAエンジンの核となる機能である。

JPQL

JPQL (Java Persistence Query Language)は、エンティティおよびエンティティに対して問い合わせを行うためのSQLライクなクエリ言語である。JPQL発行のためのAPIは、エンティティマネージャが提供している。

JPAを使ったアプリケーション開発

JPAを使ってデータベースアクセスを行うアプリケーションを開発する際に、個々のプログラマが開発する必要があるコンポーネントは、エンティティとアプリケーションである。

エンティティは、データベースのテーブル単位で作成する。エンティティのクラスはテーブルに対応し、フィールドはテーブルのカラムに対応する。エンティティでは、クラスとテーブルの関連、フィールドとカラムの関連などのメタ情報はアノテーションを使って定義する。JPAはこの情報を読み取ることで、エンティティに対する操作をSQLに置換したり、SQLの照会結果をエンティティに変換するなどの機能を実現している。

アプリケーションは、以下の2つの方法でデータベース操作を実現する。

エンティティとエンティティマネージャ

エンティティの状態遷移

エンティティは「NEW」、「MANAGED」、「DETACHED」、「REMOVED」という4つの状態を持つ。JPAでは、アプリケーションからエンティティマネージャAPIを使って、エンティティの状態変化を行うことで、永続化処理(挿入、更新、削除)を実現する。

エンティティの状態
状態 説明
NEW インスタンス化がされているだけで、永続化コンテキストにバインドされていない状態。
MANAGED 永続化コンテキストにバインドされた状態。この状態にあるエンティティに対する変更はデータベースに反映される。
DETACHED MANAGED状態だったエンティティが、永続化コンテキストからアンバインドされた状態。
REMOVED MANAGED状態のうち、エンティティが削除予約となっている状態。

上記のうち、「MANAGED」、「REMOVED」状態にあるエンティティ(=永続化コンテキストで管理しているエンティティ)が、データベースと同期化する。

エンティティの状態変化を行うためのエンティティマネージャのAPI
メソッド 説明
<T> find (Class<T> entityClass, Object primaryKey) エンティティのクラスと主キーを示すオブジェクトを引数として渡すと、対象テーブルに対して主キー検索を実行し、検索結果のエンティティオブジェクトはMANAGED状態を返却する。
void persist(Object entiry) NEW状態のエンティティを引数として渡すとMANAGED状態になる。MANAGED状態になったエンティティは、次のフラッシュのタイミングで対象テーブルに挿入する。
void remove(Object entiry) MANAGED状態のエンティティを引数として渡すと、REOVED状態になる。REOVED状態になったエンティティは、次のフラッシュのタイミングで対象テーブルから削除する。
<T> T merge(T entity) DETACHED状態のエンティティを引数として渡すと、引数として渡したエンティティのコピーをMANAGED状態にして返す。
void clear() このメソッドを呼び出すと、その時点に永続化コンテキストにバインドしている全エンティティオブジェクトがDETACHED状態になる。
void close() 現在のエンティティマネージャをクローズする。このメソッドを呼び出すと、その時点での永続化コンテキストにバインドしている全エンティティオブジェクトがDETACHED状態になる。
void flush() このメソッドを呼び出すと、JPAエンジンによってSQLを発行し、その時点での永続化コンテキスト内の全エンティティ内容を対象テーブルに反映する。通常、フラッシュのタイミングはJPAエンジンが自動的に決めるが、このメソッドを呼び出すことで明示的にフラッシュを実行できる。

データベースとの同期化

データベースにSQLを発行し、永続化コンテキストのエンティティの状態をデータベースと同期化させる処理のことを、JPAではフラッシュと呼ぶ。JPAでは、以下の3つのタイミングでフラッシュを実行する。

フラッシュのタイミング
タイミング 説明
トランザクションコミット トランザクションをコミットする直前のタイミングで、更新したエンティティがあればSQLを発行する。
JPQL発行 JPQLを発行する直前のタイミングで、更新したエンティティがあればSQLを発行する。
em.flush呼び出し アプリケーションから明示的にAPIコールを行ったタイミングで、更新したエンティティがあればSQL文を発行する。

JPAを使ってデータベース処理を実装する際は、エンティティの状態変化に加え、永続化コンテキストとデータベースの同期化のタイミングを意識してアプリケーションを組む必要がある。

JPQLとクエリオブジェクト

クエリ言語の種類

エンティティマネージャを使用したエンティティに対する直接操作では、条件付き検索や複数レコードの一括更新、削除といったデータベース処理は実装できない。このような場合は、クエリ言語を使用する。JPAでは以下のクエリ言語が使用可能である。

クエリ言語の種類
クエリ言語 説明
JPQL JPAが提供するSQLライクなクエリ言語(データベース非依存)
実行結果をエンティティとして取得できる
ネイティブSQL データベース製品固有のSQLを記述するための機能
JPQLでは対応していないデータベース固有のSQLを発行できる

JPAを利用する場合、基本的にはJPQLを使用する。ネイティブSQLを使用するのは、ストアドプロシージャの呼び出しなど、JPQLでは提供を行っていないデータベース固有のSQLを発行する必要がある場合である。

クエリオブジェクト

クエリオブジェクトは、クエリを発行するためのインタフェースである。クエリオブジェクトは、エンティティマネージャから取得する。

クエリオブジェクトの取得を行うためのエンティティマネージャのAPI
メソッド 説明
Query createQuery(String qlString) 指定したJPQLを発行するためのクエリを生成する。
Query createNativeQuery(String sqlString) 指定したSQL文を発行するためのネイティブクエリを生成する。
Query createNativeQuery(String sqlString, Class resultClass) 指定したSQL文を発行するためのネイティブクエリを生成する。実行結果にマッピングするクラスオブジェクトを指定する。
Query createNativeQuery(String sqlString, String resultSetMapping) 指定したSQL文を発行するためのネイティブクエリを生成する。実行結果にマッピングする結果セットマッピングを指定する。
クエリオブジェクトに用意されている代表的なAPI
メソッド 説明
int executeUpdate() UPDATE文、DELETE文を実行するためのインタフェース。戻り値は更新件数。
Object getStringResult() SELECT文を実行するためのインタフェース。照会結果が1行の場合に使用する。
Object getResultList() SELECT文を実行するためのインタフェース。照会結果が1行以上の場合に使用する。
Query setParameter(int position, Object value) JPQLのパラメータ変数にパラメータ値を位置指定でバインドする。
Query setParameter(String name, Object value) JPQLのパラメータ変数にパラメータ値を名前指定でバインドする。

エンティティの開発

エンティティの作成単位

エンティティクラスは、データベースのテーブル単位に作成する。また、エンティティクラスには、マッピング対象のカラム単位にフィールド属性を定義する。

アノテーションによるマッピング情報の定義

エンティティとテーブル間のマッピング定義のようなメタ情報は、アノテーションを使用して定義する。

JPQL (Java Persistence Query Language)

JPQL (Java Persistence Query Language) は、関係データベースに格納されたエンティティに対するクエリに使用される。文法的にはSQLに似ているが、データベースの表を直接操作するのではなく、エンティティオブジェクトを操作する。

JPQLの基本書式

SELECT ... FROM ... [WHERE ...] [GROUP BY ...] [HAVING ...] [ORDER BY ...]

DELETE FROM ... [WHERE ...]

UPDATE ... SET ... [WHERE ...]

パラメータの指定方法

位置指定方式

識別子「?」と任意の数字の組み合わせでパラメータを指定する。

Query query = em.createQuery("SELECT u FROM User u WHERE u.country=?1 and u.age > ?2");

query.setParameter(1, "japan");
query.setParameter(2, 60);

名前指定方式

識別子「:」と任意の文字列の組み合わせでパラメータを指定する。

Query query = em.createQuery("SELECT u FROM User u WHERE u.country=:country and u.age > :age");

query.setParameter(country, "japan");
query.setParameter(age, 60);

JPQLで利用可能な関数

JPSQLで使用可能な関数を以下に示す。

関数名 SELECT句 HAVING句 WHERE句 説明
DISTINCT 重複の排除
COUNT(string) 件数
MAX(string) 最大値
MIN(string) 最小値
AVG(string) 平均
SUM(string) 合計
CONCAT(string1, string2) 文字列の連結
SUBSTRING(string1, start, end) 文字列の一部を取得
TRIM(string) 文字列の空白を除去
UPPER(string) 大文字に変換
LOWER(string) 小文字に変換
LENGTH(string) 文字列の長さを取得
LOCATE(string1, string2) string1内でstring2が出現する位置
ABS(number) 絶対値
SQRT(number) 平方根
MOD(number1, number2) number1をnumber2で割った余り
SIZE(collection) コレクションの要素数
CURRENT_DATE DBの日付を返す
CURRENT_TIME DBの時刻を返す
CURRENT_TIMESTAMP DBのタイムスタンプを返す

JPQLで利用可能な演算子

JPQLのWHERE句で利用可能な演算子を以下に示す。

分類 演算子 備考
算術演算子 加算 +
減算 -
乗算 *
除算 /
論理演算子 集合積 AND
集合和 OR
否定 NOT
関係演算子 等号 =
不等号 <>
比較 < 数値フィールドに対してのみ有効
> 数値フィールドに対してのみ有効
<= 数値フィールドに対してのみ有効
>= 数値フィールドに対してのみ有効
特殊演算子 判定 BETWEEN 数値フィールドに対してのみ有効
IN
LIKE 「%」、「_」が使用可能
IS NULL
IN EMPTY Collection型フィールドの空判定

例外

EntityExistsExeption

javax.persistence.EntityExistsExeptionは、EntityManager.persit(Object)が呼ばれたときに既にエンティティが存在した場合、永続化プロバイダによって投げられる例外である。たとえば、データベースにレコードを挿入しようとしたときに一意制約違反が発生した場合など。