JPA(Java Persistence API)とは、リレーショナルデータベースのO/Rマッピングを行うためのフレームワークです。JPA仕様を実装したものとして、Spring Data JPAやHibernateなどが挙げられる。
JPA (Java Persistence API)は、O/Rマッピング・アーキテクチャのJava用フレームワークである。Javaオブジェクトをデータベースに格納したり、データベースのデータをJavaオブジェクトに変換する処理を自動化したりするため、JDBCを直接使用するのに比べ、簡素なプログラムコードでデータベース処理を実現できる。
JDBCを直接使用するアプリケーションは、製品固有のSQLに依存したコードがネックとなり、その移植性を阻害していたが、JPAは製品間の違いを多く吸収するため高い移植性を保つことができる。
JPAでは、Javaオブジェクトとデータベースのテーブル間のマッピング情報を、アノテーションを用いて定義する。これにより、エンティティをPOJO (Plain Old Java Object)で実装できたり、複雑な定義ファイルを作成する必要が無くなるなど、開発容易性を確保することができる。
エンティティとは、データベースのテーブルに関連付けるJavaBeansである。エンティティはPOJO (Plain Old Java Object)として実装し、データベーステーブルとの関連は、アノテーションを使って定義する。エンティティ操作のためのAPIは、エンティティマネージャが提供する。
エンティティマネージャは、アプリケーションに対してCRUD操作のためのインタフェースを提供する。また、永続化コンテキスト上のエンティティの状態管理と、エンティティとデータベース間の同期化を行う。
永続化コンテキストは、エンティティマネージャが管理する、メモリ上のエンティティの集合である。エンティティマネージャは、コンテキスト上のエンティティオブジェクトとライフサイクルを管理する。
エンティティマネージャファクトリは、エンティティマネージャを生成するファクトリの役割を果たす。
永続化ユニットは、エンティティマネージャ単位に用意する。永続化に関する構成情報(エンティティクラス、データソース等)を保持するリポジトリである。定義情報は、XMLファイル(persistence.xml)に定義する。
EJBコンテナ、またはアプリケーションから呼び出され、エンティティマネージャファクトリを生成する。JPAエンジンの核となる機能である。
JPQL (Java Persistence Query Language)は、エンティティおよびエンティティに対して問い合わせを行うためのSQLライクなクエリ言語である。JPQL発行のためのAPIは、エンティティマネージャが提供している。
JPAを使ってデータベースアクセスを行うアプリケーションを開発する際に、個々のプログラマが開発する必要があるコンポーネントは、エンティティとアプリケーションである。
エンティティは、データベースのテーブル単位で作成する。エンティティのクラスはテーブルに対応し、フィールドはテーブルのカラムに対応する。エンティティでは、クラスとテーブルの関連、フィールドとカラムの関連などのメタ情報はアノテーションを使って定義する。JPAはこの情報を読み取ることで、エンティティに対する操作をSQLに置換したり、SQLの照会結果をエンティティに変換するなどの機能を実現している。
アプリケーションは、以下の2つの方法でデータベース操作を実現する。
エンティティは「NEW」、「MANAGED」、「DETACHED」、「REMOVED」という4つの状態を持つ。JPAでは、アプリケーションからエンティティマネージャAPIを使って、エンティティの状態変化を行うことで、永続化処理(挿入、更新、削除)を実現する。
状態 | 説明 |
---|---|
NEW | インスタンス化がされているだけで、永続化コンテキストにバインドされていない状態。 |
MANAGED | 永続化コンテキストにバインドされた状態。この状態にあるエンティティに対する変更はデータベースに反映される。 |
DETACHED | MANAGED状態だったエンティティが、永続化コンテキストからアンバインドされた状態。 |
REMOVED | MANAGED状態のうち、エンティティが削除予約となっている状態。 |
上記のうち、「MANAGED」、「REMOVED」状態にあるエンティティ(=永続化コンテキストで管理しているエンティティ)が、データベースと同期化する。
メソッド | 説明 |
---|---|
<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を使ってデータベース処理を実装する際は、エンティティの状態変化に加え、永続化コンテキストとデータベースの同期化のタイミングを意識してアプリケーションを組む必要がある。
エンティティマネージャを使用したエンティティに対する直接操作では、条件付き検索や複数レコードの一括更新、削除といったデータベース処理は実装できない。このような場合は、クエリ言語を使用する。JPAでは以下のクエリ言語が使用可能である。
クエリ言語 | 説明 |
---|---|
JPQL | JPAが提供するSQLライクなクエリ言語(データベース非依存) 実行結果をエンティティとして取得できる |
ネイティブSQL | データベース製品固有のSQLを記述するための機能 JPQLでは対応していないデータベース固有のSQLを発行できる |
JPAを利用する場合、基本的にはJPQLを使用する。ネイティブSQLを使用するのは、ストアドプロシージャの呼び出しなど、JPQLでは提供を行っていないデータベース固有のSQLを発行する必要がある場合である。
クエリオブジェクトは、クエリを発行するためのインタフェースである。クエリオブジェクトは、エンティティマネージャから取得する。
メソッド | 説明 |
---|---|
Query createQuery(String qlString) | 指定したJPQLを発行するためのクエリを生成する。 |
Query createNativeQuery(String sqlString) | 指定したSQL文を発行するためのネイティブクエリを生成する。 |
Query createNativeQuery(String sqlString, Class resultClass) | 指定したSQL文を発行するためのネイティブクエリを生成する。実行結果にマッピングするクラスオブジェクトを指定する。 |
Query createNativeQuery(String sqlString, String resultSetMapping) | 指定したSQL文を発行するためのネイティブクエリを生成する。実行結果にマッピングする結果セットマッピングを指定する。 |
メソッド | 説明 |
---|---|
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) は、関係データベースに格納されたエンティティに対するクエリに使用される。文法的にはSQLに似ているが、データベースの表を直接操作するのではなく、エンティティオブジェクトを操作する。
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);
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のWHERE句で利用可能な演算子を以下に示す。
分類 | 演算子 | 備考 | |
---|---|---|---|
算術演算子 | 加算 | + | |
減算 | - | ||
乗算 | * | ||
除算 | / | ||
論理演算子 | 集合積 | AND | |
集合和 | OR | ||
否定 | NOT | ||
関係演算子 | 等号 | = | |
不等号 | <> | ||
比較 | < | 数値フィールドに対してのみ有効 | |
> | 数値フィールドに対してのみ有効 | ||
<= | 数値フィールドに対してのみ有効 | ||
>= | 数値フィールドに対してのみ有効 | ||
特殊演算子 | 判定 | BETWEEN | 数値フィールドに対してのみ有効 |
IN | |||
LIKE | 「%」、「_」が使用可能 | ||
IS NULL | |||
IN EMPTY | Collection型フィールドの空判定 |
javax.persistence.EntityExistsExeptionは、EntityManager.persit(Object)が呼ばれたときに既にエンティティが存在した場合、永続化プロバイダによって投げられる例外である。たとえば、データベースにレコードを挿入しようとしたときに一意制約違反が発生した場合など。