Maven
jpa
JPQL
JavaSE
DatebaseManager
JavaDay 13

データベースを簡単にーJavaSEでもオブジェクト指向データベース(JPA)

More than 1 year has passed since last update.

この記事は、Java Advent Calendar 2016 の13日目の記事です。

前日は、kodukiさんの「さあ、並列プログラミングをはじめよう」 でした。

明日は、enkさんの「JGiven で 100% Pure Java BDD」 です。


はじめに

 筆者は、今、入門者向けのオブジェクト指向の本を制作中です。いろいろ新しい試みを盛り込んでいるのですが、今日は、その解説の中からJPAについてお話しようと思います。JPAでは、Javaのオブジェクトをそのままデータベースに読み書きできます。これまでのデータベース操作を驚くほど簡単に、そして、楽しくしてくれる技術です。

 しかも、JPAは、JSRで定義されているJava標準技術の1つ(JSR338: Java Persistence API 2.1)です。つまり、Java言語の世界では、データベース利用の標準技術ということですね。

 「知らなかった!」などと思った人は、ぜひ、この記事を読んでみてください。そして、今日からJPAを使い始めましょう!


1.JPAって何?

A0660.png

 JPAはJava Persistence APIの略です。Persistenceは、永続性とか持続性などという意味なので、オブジェクトをそのままの形で永続的に保管したり、取り出したりするためのAPIという意味です。

 同じようなことは、ObjectInputStreamやObjectOutputStreamを使ってもできます。これらを使うと、オブジェクトをファイルに保管することができます。しかし、JPAはファイルではなく、データベースに保管するところが大きな違いです。簡単なJava言語のメソッドだけで操作できるので、従来のように、JDBCやSQLを使う必要はありません。

 もちろん、データベースの世界とオブジェクトの世界とは、水と油ほども違うので、両者のつじつま合わせをする技術(ORM: Object Relational Mapping)の理解も必要ですが、それも今では、簡単なアノテーションをソースコードに書き加えるだけでいいことになっているので、簡単です。これについては、また別の機会にお話します。

 さらに、いくらJPAが簡単だといっても、そのまま使うのは学習段階までの話。JPAを使って何か作る時には、使いやすくするライブラリがあると便利です。そこで、DatabaseManagerというユーティリティクラスを使います。

 DatabaseManagerは、筆者が本の中で使うために作成したユーティリティで、JPAを手軽に利用できます。本稿では、DatabaseManagerの使用を前提にお話しします。


2.使い方は簡単

 実際、どれくらい簡単なのか例を見てください。

 次の表のような商品のリストがあるとします。

A0900.png

 これがデータベースに保管するデータ(横1行が1つのオブジェクトになる)の一覧です。

 表から、商品オブジェクトのクラスを次のように作成しておきます。

@Entity

public class Product {
@Id
private String number; // 型番
private String name; // 品名
private int price; // 価格
private LocalDate date; // 発売日
private boolean stock; // 在庫(の有無)

  // コンストラクタ、ゲッター、セッター、toStringメソッドは記載を省略
}

 ここで、@Entityというアノテーションは、オブジェクトの世界とリレーショナルデータベースの世界の橋渡しをするためのものですから、忘れずに書いてください。また、@Idというアノテーションは、主キーとなるフィールドに必ず付けることになっています。

 クラスを作成する上での注意点は次のようです。

A0910.png

 Productクラスの各フィールドは、String、int、LocalDate、booleanといった、Java言語でよく使う型を並べてみました。このうち、LocalDate型は、Java8から使えるようになった標準の日付型ですが、問題なく使用できます。

 そして次は、Productクラスのインスタンス p1 を作成して、データベースに保存するプログラムです。

 どうでしょう、わずか3行で書けてしまいました!

1   Product p1 = new Product("A100", "XenPad", 36760, LocalDate.parse("2016-09-16"), true);

2 DatabaseManager<Product> dbm = new DatabaseManager<>(Product.class);
3 dbm.persist(p1); // データベースに保管

A0680.png

【プログラムの説明】

 データベースに保管するオブジェクトは、エンティティと呼ぶきまりなので、以下ではこの用語を使います。1行目は、Productクラスのインスタンス、つまりProductクラスのエンティティの作成です。エンティティを作成してProduct型の変数p1にセットしています。

 2行目は、データベースマネージャーの作成です。DatabaseManagerクラスは、JPAを簡単に使えるようにするユーティリティクラスで、そのコンストラクタは次のような定義です。

    public DatabaseManager(Class<T> type)       // コンストラクタ

 総称型になっているので、保管するインスタンスの型に合わせて生成します。引数はエンティティのクラス情報ですから、例の場合は、Product.classを指定します。

    DatabaseManager<Product> dbm = new DatabaseManager<>(Product.class);

 他にも少し、例をあげてみましょう。例えば、Employee型やMember型がある時、それらのインスタンスを操作する場合は、それぞれ次のようにデータベースマネージャーを作成します。

    DatabaseManager<Employee> dbm1 = new DatabaseManager<>(Employee.class);

DatabaseManager<Member> dbm2 = new DatabaseManager<>(Member.class);

 そして最後に、3行目がデータベースへの保管です。保管はデータベースマネージャーのpersistメソッドで、引数にエンティティを指定するだけです。とても簡単ですね。

3   dbm.persist(p1);    // データベースに保管


3. DatabaseManagerはJPAを簡単にする

 JPAでは、EntityManagerというインタフェースが持つメソッドを使って、各種の操作をします。EntityManager には、persist(新規保存)、remove(削除)、merge(更新)、find(検索)などの基本メソッドがありますが、JavaSEで使う場合は、面倒な書き方をしなくてはいけません。

 というのも、データベースは同時アクセスや障害への対策が必要ですから、トランザクションの中で行う必要があります。JavaEEでは、トランザクションは自動的に働くので何もしなくていいのですが、JavaSEではトランザクションを自前で実行しなくてはいけません。そのため、例えば次のように冗長なプログラムになってしまいます。

1   EntityManagerFactory emf = Persistence.createEntityManagerFactory("pesistenceUnitName");

2 EntityManager em = emf.createEntityManager();
3 em.getTransaction().begin();
4 em.persist(emp);
5 em.getTransaction().commit();
6 em.close();

 1、2行がEntityManagerの取得、3行でトランザクションを開始し、4行で保存処理、5行でトランザクションを終了して、6行でEntityManagerを棄却します。どれも単純な処理ですが、メソッド実行の度にこれをやるのは面倒ですね。

 そこで、このような処理を1つのメソッドに作り込んであるのが、DatebaseManagerクラスです。すでに見たように、これを使うと、同じ処理をわずが1行で書けます。

    dbm.persist(p1);    // データベースに保管

 ところで、EntitityManagerの機能の中には、JPQLというオブジェクトベースのクエリ言語(SQLみたいなもの)を実行する機能があります。そこで、DataBaseManagerでも、よく使うクエリを1つのメソッドにして用意してあります。また、クエリを自分で書いて実行したい時のために、クエリ文字列を受け取って実行するメソッドもあります。

DatebaseManagerクラスのソースコードは、「5.JPAプログラムの書き方」の節にダウンロードリンクがあります。


情報はどこに?

 JavaSEで使うJPAについて詳しく知りたい場合は、著者の近刊を御覧いただくのがベストですが、そうすると来年まで待たなくてはならないので、今すぐ知りたい人のために、いくつかのリソースをお知らせしておきます。

 ●JPA全般について

  Java Day Tokyo 2014での講演記事「はじめてのJPA--シンプルで使いやすい、Java EEのデータ永続化機能の基本を学ぶ」

 ●JPAの詳細

  「わかりやすいJavaEE」の15、16章(JPA)、17章(ORM)、18章(JPQL)

  これはJavaEE版ですが、違いは実行方法だけですから、書かれている知識自体はJavaSEでも共通です。

 ●JPQLの書き方

  ブログ記事「わかりやすいJPA(1)~(12)」

  JPQLを書いてすぐに動かして試すことができるプログラムも配布しています。

  プログラムのインストール方法を解説する動画もありますよ。


4.JavaSEでJPAを使うには(実行環境を準備する)

A0700.png

 JPA(とDatabaseManager)を使うとデータベース処理がとても簡単になることがわかったと思います。この後、動かして試せる例題を見ていただきますが、その前に、みなさんの手元でも実行できるように、実行環境の設定についてお話します。


(1) Mavenプロジェクトの作成

 JavaSEでJPAを使うには、JPAに関係するライブラリが必要ですが、たくさんあるので、すべてを手書きで指定するのは現実的ではありません。そこで、Mavenというツールを使って、必要なライブラリを指定することにしましょう。

 Mavenの機能は、ライブラリ名やバージョンを指定するだけで、自動的にライブラリ(jarファイル)をダウンロードしてくれることです。しかも、核になるライブラリを指定するだけで、依存関係のあるすべてのライブラリを自動的にダウンロードします。

 EclipseやNetBeansといった代表的なIDEは、Mavenを最初からプラグインとして組み込んだ状態になっているので、Mavenを使うには、単に「Mavenプロジェクト」を作成すればよいのです。

 ここではEclipseの例を説明します。

 Eclipseでは、最初に普通のプロジェクトを作っておいて、それをMavenプロジェクトに変換すると、環境をあまり変えずにMavenを使うことができます。

【EclipseにおけるMavenプロジェクトの作成】

①dbsample(名前は任意)という普通のJavaプロジェクトを作成する

②プロジェクトを右ボタンでクリックし、[構成]⇒[Mavenプロジェクトへ変換]を選択する

③ダイアログが開くので、そのまま[OK]ボタンを押す


(2) pom.xmlファイルをコピペする

 プロジェクトができると、pomファイルが開かれた状態になっているので、エディタの下段にある[pom.xml]と書かれたタブをクリックします。すると、pomファイルのソースコードが表示されます。

A0560.png

A0890.png

 pom.xmlは、Mavenへの指令を集めたファイルです。

 ざっと目を通してみると、プロジェクトの名前(dbsample)や、ソースコードのディレクトリ名(src)、そして、使用するjavaコンパイラのバージョン(1.8)などが書かれています。

 後は、この中にJPAに必要なライブラリを追記するだけです。JPAを使うのに必要なライブラリは次の4つです。

A0720.png

 これらのライブラリを、タグを使ってpom.xmlに追記します。

 次がその書き方のお手本ですから、これをそのままコピーして使ってください。

    <dependencies>

<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.5.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.3.3.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-java8</artifactId>
<version>5.2.5.Final</version>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
<version>10.13.1.1</version>
</dependency>
</dependencies>

※お手本はこちらからもダウンロードできます。

 これらは、依存性(dependency)の記述といい、プロジェクトが依存しているライブラリ、つまり必要なライブラリを記述しただけのものです。タグは、groupidがライブラリの作成者、artifactIdがライブラリ名、そしてversionがライブラリのバージョンを表しています。

 これを、そのまま次の図のように張り付けて、保管ボタンを押してください。

A0600.png

 保管をボタンを押すと、左欄に[Maven依存関係]というフォルダが出来、その中に、たくさんのJarファイルが出現します。これらがMavenによりダウンロードされたライブラリファイルです。


(3) dependencyの書き方を調べるには

 実は、上記のお手本は、MVN REPOSITORYというサイトからコピペしてきたものです。MVN REPOSITORYの中でライブラリ名を検索すると、最新バージョンのリストやタグの書き方を調べることができます。試してみると面白いですよ。

MVN REPOSITORY (https://mvnrepository.com/)

A0590.png

① "hibernate-core"で検索し、

②結果からhibernate-coreをクリックして、

③表示されたリストから5.25 Final という最新バージョンをクリックする。

以上で表示されるのが上図。コピペすべきタグが表示されます。 


(4) persistence.xmlファイルをコピペする

 あと1つだけ必要なファイルがあります。それは、データベースとJavaプログラムを接続するための設定ファイル(persistence.xml)です。このファイルは、ソースコードを入れるsrcフォルダにMETA-INF(この名前は変更不可)というフォルダを作り、その中に作成します。

A0630.png

A0730.png

 最初に、srcフォルダの中にMETA-INFという名前のフォルダを作ってください。それから、META-INFフォルダの中に、pesistence.xmlという名前(綴りを間違わないように)のファイルを作成します。次の手順で作成します。

【作成手順】

①srcフォルダを右クリックし、[新規]⇒[フォルダ]と選択する

②ダイアログが開くので、フォルダ名にMETA-INF と入力して[完了]ボタンを押す

③META-INFフォルダを右クリックし、[新規]⇒[ファイル]と選択する

④ダイアログが開くので、ファイル名にpersistence.xmlと入力して[完了]ボタンを押す

  

 さて、次がpersistence.xmlのお手本です。

 これを作成したファイルにコピペして、保管ボタンを押してください。

【persistence.xmlファイルのお手本】

A0740.png

お手本はこちらからダウンロードできます。

《説明》


<1>青字の部分について

・default_pu

 この設定ファイルの名前です。DatabaseManagerのコンストラクタでは、この名前をデフォルト値として使っています。変更可能ですが、変更した場合はDatabaseManagerのインスタンスを作成する時、変更した名前を指定する必要があります。DatabaseManagerのコンストラクタを参照してください。

・mydb

 データベース名です。好きな名前に変更してかまいません。

・root、rootpw

 データベースのユーザー名とパスワードです。必要に応じて変更してください。

<property name="hibernate.hbm2ddl.auto" value="create" />

 プログラムを実行する前に、既存のデータ(データベースのテーブル)をすべて削除し、新しく必要なテーブルを作成してから始める、という指定です。つまり、毎回テーブルがクリアされます。今回の例題を実行する時にはこのままにしておきます。

 ただし、実務で使うプログラムの場合は、最初に1回だけこのまま動かし、2回目を動かす前に削除してください。1回目だけ付けておくのは、データベーステーブルを自動作成してくれるからです。このタグは、基本的には、開発時(あるいは学習用)にだけ使用するものです。


<2>タグの機能の概要

<persistence version="2.1" ・・・

JPAのバージョンが2.1であることを表しています。

 

<persistence-unit name="default_pu" transaction-type="RESOURCE_LOCAL">

persistence.xmlに付ける論理名とトランザクションタイプを指定します。トランザクションタイプは、JavaSEではRESOURCE_LOCALを、JavaEEではJTAを指定します。JavaSEでは、いつもこのように書いて構いません。

 

<property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver" />

データベースドライバを指定します。使用するデータベースごとに違う指定になります。

org.apache.derby.jdbc.EmbeddedDriverは、JavaDB(Derby)を組み込みモードで使う時のドライバです。対応するライブラリをMavenのPom.xmlに指定しなくてはいけません。pom.xmlで指定しているderbyがそれです。

 

<property name="hibernate.dialect" value="org.hibernate.dialect.DerbyDialect" />

使用するRDBの種類ごとに最適化したSQLを生成するための指定です。使用するRDBにより設定する名前が違います。Hibernateのドキュメントには一覧表が掲載されています。

 

<property name="hibernate.show_sql" value="true" />

<property name="hibernate.format_sql" value="true" />

JPAでの処理は、SQLに変換して実行されます。このタグは実行時のSQLログをコンソールに出力する指定です。大変わかりやすいSQLが表示されるので、デバックやチューニングにとても役立ちます。

 


(5) MySQLを使うには

A0760.png

 MySQLを使う時も、pom.xmlとpersistence.xmlを少し書き換えるだけです。青字の部分が違うところです。なお、こちらは、組み込み型ではなく、サーバー型のRDBです。

 pom.xmlではMySQLのドライバがいるので当然ライブラリが違ってきます。また、persistence.xmlでは、ドライバクラス名やデータベースサーバーのURLが違います。また、SQLを最適化するタグでは、MySQL用の書き方をします。

pom.xmlの依存性記述の部分

A0770.png

persistence.xml

A0780.png

※2つのファイルは、こちらから一括してダウンロードできます。


5.JPAプログラムの書き方

A0920.png

★以下の例題プログラムと設定ファイルをこちらからダウンロードしてください。

★DatabaseManagerとサンプルプログラムのソースコード、persistence.xml、pom.xml が含まれます。

★データベースにderbyを使う場合と、MySQLを使う場合の2つを同梱しています。


(1) エンティティを保存する

 まず、次のSample01は、先ほど示したインスタンスを保存する例の完全版です。

package sample;

import entities.Product;
import java.time.LocalDate;
import com.tkxwebs.dbutil.DatabaseManager;

public class Sample01 {
public static void main(String[] args) {
Product p1 = new Product("A100", "XenPad", 36760, LocalDate.parse("2016-09-16"), true);
DatabaseManager<Product> dbm = new DatabaseManager<>(Product.class);
dbm.persist(p1); // 保存する
dbm.close(); // 終了
}
}

 最後に、closeメソッドを実行しています。closeはプログラムの終了時に1回だけ実行します。DatabaseManagerのメソッドをいくつか実行する場合でも、一連の操作の後で、プログラムの終了時に1回だけ実行します。


(2) 全てのエンティティを取得する

 Sample02は、getAllメソッドでデータベースの中にあるすべてのエンティティを取得する例です。JPAでは、検索結果をエンティティのリストとして取得できるので、その後の処理が簡単です。

package sample;

import java.time.LocalDate;
import java.util.List;
import com.tkxwebs.dbutil.DatabaseManager;
import entities.Product;

public class Sample02 {
public static void main(String[] args) {
DatabaseManager<Product> dbm = new DatabaseManager<>(Product.class);
init(dbm); // 5件のエンティティを登録する

// 全データを入れたリストを取得する
List<Product> ls = dbm.getAll();

// 結果の確認
for(Product p : ls) { // リストの内容を表示する
System.out.println(p);
}
dbm.close(); // 終了
}
// 5件のデータをデータベースに登録する
public static void init(DatabaseManager<Product> dbm) {
Product p1 = new Product("A100", "XenPad", 36760, LocalDate.parse("2016-09-16"), true);
Product p2 = new Product("A200", "CoolPad", 22898, LocalDate.parse("2016-07-08"), true);
Product p3 = new Product("A300", "jPad Pro", 60000, LocalDate.parse("2016-03-31"), true);
Product p4 = new Product("A400", "jPad Air2", 45199, LocalDate.parse("2014-10-17"), true);
Product p5 = new Product("A500", "AsusPad", 32000, LocalDate.parse("2015-09-19"), true);
dbm.persist(p1);
dbm.persist(p2);
dbm.persist(p3);
dbm.persist(p4);
dbm.persist(p5);
}
}

A0800.png

 今回の解説のサンプルでは、persistence.xmlの設定により、プログラムの開始前に、まず、既存のデータ(データベースのテーブル)を消去し、新しく空のテーブルを再作成するようになっています(これは変更できます)。これに合わせて、mainメソッドは、最初にinitメソッドを実行して、5件のエンティティをデータベースに保管した後で、何かの具体的な処理を行うようにしています。これは、後の例でも同じですから、覚えておいてください。

 Sample02では、initメソッドを実行した後、getAllメソッドを実行して全エンティティを格納したリストを取得しています。

 つまり、次の行がポイントです。

    List<Product> ls = dbm.getAll();    // 全データを入れたリストを取得する

 このように、getAllメソッドでは、結果をリストとして取得できるので、拡張for文ですべてのエンティティを表示できます。

    for(Product p : ls) {               // リストの内容を表示する

System.out.println(p);
}

 ただし、上記は、ラムダ式を使うと次のように書くことができます。1行で書けるので便利ですね。これ以降の例題では、この書き方を使って簡潔に書くことにします。

    ls.forEach(e -> System.out.println(e)); // リストの内容を表示する


(3)削除、検索、更新の処理

 新規に保管する例はsample01で見ましたので、ここでは削除、検索、更新の例です。いわゆるCRUD(Create、Read、Update、Delete)と言われる基本処理ですが、これもDatabaseManagerのメソッドを使うだけで簡単に実行できます。

package sample;

import java.time.LocalDate;
import java.util.List;
import com.tkxwebs.dbutil.DatabaseManager;
import entities.Product;

public class Sample03_ {
public static void main(String[] args) {
DatabaseManager<Product> dbm = new DatabaseManager<>(Product.class);
init(dbm); // データベースに5件のエンティティを保管する

// 削除(A200のキーのエンティティを削除)
dbm.remove("A200");

// 検索(A400のキーのエンティティを検索)
Product target = dbm.find("A400");

// 更新(検索したエンティティの価格を変更して更新)
target.setPrice(50000);
dbm.merge(target);

// 結果の確認
List<Product> ls = dbm.getAll();
if(ls != null) {
ls.forEach(e -> System.out.println(e));
}
dbm.close(); // 終了
}
// initメソッドは記載を省略
}

A0810.png

※numberがA200のエンティティは削除されている

※numberがA400のエンティティは価格が50000に変更されている

 

 データベスマネージャーのメソッドを使うだけですから簡単ですね。

 削除や検索は、主キー(Productではnumber)の値を指定して実行します。また、更新は引数に更新するエンティティを指定して実行するだけです。


(4)並べ替え(ソート)して全件を取得する

A0930.png

 Sample04は指定したフィールドの昇順に並べ替えた状態で、全エンティティを取得する例です。例では、日付順で並べ替えるので、getAllに日付フィールドの名前を指定しています。

package sample;

import java.time.LocalDate;
import java.util.List;
import com.tkxwebs.dbutil.DatabaseManager;
import entities.Product;

public class Sample04 {
public static void main(String[] args) {
DatabaseManager<Product> dbm = new DatabaseManager<>(Product.class);
init(dbm);

// 日付順に並べ替えて全件を取得する
List<Product> ls = dbm.getAll("date");

// 結果の確認
if(ls != null) {
ls.forEach(e -> System.out.println(e));
}
dbm.close(); // 終了
}
// initメソッドは記載を省略
}

A0830.png

 結果を見ると確かに日付順で並んでいることがわかります。昇順の並べ替えがデフォルトですが、降順に並び替えたい場合は、次のように、引数にtrueを追加します。もちろん、falseを追加した場合は昇順になります。

List<Product> ls = dbm.getAll("date", true);        // 降順に並び替えて全件を取得する


(5)総件数を取得する & 指定位置から最大n件取得する

 データベースに多数のエンティティが保管されている時、全部を一度に取り出すとメモリーを圧迫します。そこで、sample05は、「〇件目から最大◎件を取り出す」という処理です。

 これらのメソッドは、画面1ページに表示するデータの件数を決めておいて、ページ単位の表示制御を行う処理(pagination)に使用できます。

package sample;

import java.time.LocalDate;
import java.util.List;
import com.tkxwebs.dbutil.DatabaseManager;
import entities.Product;

public class Sample05 {
public static void main(String[] args) {
DatabaseManager<Product> dbm = new DatabaseManager<>(Product.class);
init(dbm);

// 総件数の取得と表示
System.out.println("総件数=" + dbm.count() + "件");

// 先頭から最大3件取得する
List<Product> ls = dbm.get(0, 3);

// 結果の確認
if(ls != null) {
ls.forEach(e -> System.out.println(e));
}
dbm.close(); // 終了
}
// initメソッドは記載を省略
}

A0940.png

 注意しなければいけないのは、先頭を1ではなく0から数えることです。つまり、先頭データは0件目となることに注意してください。

プログラムでも、 dbm.get(0, 3) と指定しています。


(6)クエリ(自由な検索式)を指定して検索する

A0850.png

 クエリの作成には、JPQLという問い合わせ言語が使えます。JPQLについては、さすがに本稿では解説する余裕がありません。本には詳しく書きますが、当面は「わかりやすいJavaEE」の18章やブログの解説記事「わかりやすいJPA」を見てください。

 Sample06では、金額の範囲が30,000円以上から40,000円未満までのデータを検索するクエリを実行しています。

package sample;

import java.time.LocalDate;
import java.util.List;
import com.tkxwebs.dbutil.DatabaseManager;
import entities.Product;

public class Sample06 {
public static void main(String[] args) {
DatabaseManager<Product> dbm = new DatabaseManager<>(Product.class);
init(dbm);

// クエリを指定して実行する
String query = "SELECT c FROM Product c WHERE c.price >=30000 and c.price < 40000";
List<Product> ls = dbm.select(query);

// 結果の確認
if(ls != null) {
ls.forEach(e -> System.out.println(e));
}
dbm.close(); // 終了
}
// initメソッドは記載を省略
}

A0860.png

 JPQLはJavaのオブジェクトを使って記述する問い合わせ言語です。

 JPQLのクエリは文字列で指定します。クエリの中にある c は識別変数といって、対象となるオブジェクトを表します。したがって、c.priceはオブジェクトのフィールドpriceを意味します。このように、オブジェクトにドットを打ってメンバを指定する書き方をパス式といいます。

 JPQLはオブジェクトを使って条件を記述するところに大きな特徴があります。今回は、紹介できませんが、フィールドメンバがオブジェクトの時も、パス式を使うとそのオブジェクトのメンバを指定できるのでとても強力な検索式を書くことができます。


(7)パラメータ付きのクエリを実行する

 前例では、30000とか40000のような数値をクエリの中に書いていましたが、JPQLでは、その部分をパラメータにしてクエリを作成しておき、実行時にパラメータの値を決めるという使い方ができます。

 Sample07は、前例の金額部分をパラメータにしておいて、あとから値をセットする方法を示しています。

package sample;

import java.time.LocalDate;
import java.util.List;
import com.tkxwebs.dbutil.DatabaseManager;
import entities.Product;

public class Sample07 {
public static void main(String[] args) {
DatabaseManager<Product> dbm = new DatabaseManager<>(Product.class);
init(dbm);

// パラメータ付きクエリにパラメータをセットして実行する
String query = "SELECT c FROM Product c WHERE c.price >= ?1 and c.price < ?2";
Object[] param = { 30000, 40000};
List<Product> ls = dbm.select(query, param);

// 結果の確認
if(ls != null) {
ls.forEach(e -> System.out.println(e));
}
dbm.close(); // 終了
}
// initメソッドは記載を省略
}

A0870.png

 クエリの中で ?1 とか ?2 と書かれている部分がパラメータです。パラメータはいくつでも指定できます。パラメータにセットする値は、Objectの配列型で作成し、selectメソッドの2番目の引数として指定します。

 整数の配列なのにObjectの配列にするので不思議な感じがするかもしれませんが、これはどんな値でもパラメータに埋め込めるようにする工夫です。配列要素の整数は、Javaのオートボクシング機能によって、Integerに変換されます。

 DatabaseManagerのAPIの表を見るとわかるように、クエリを実行する場合でも、「該当したデータのうち〇件目から最大◎件を取得する」というメソッドがあります。なお、並び替えは、order by ~ という書き方を追加することで、クエリの中に書けるので、メソッドは用意してありません。


6.DatabaseManagerのAPI

 最後にDatabaseManagerのAPIをまとめて示します。

A0880.png