先ほどのApplication.javaのindex()メソッドを下記のように修正してください。
package controllers;
import java.util.List;
import models.Child;
import models.Parent;
import play.db.ebean.Model.Finder;
import play.mvc.Controller;
import play.mvc.Result;
public class Application extends Controller {
public static Result index() {
// 親1の作成
Parent parent1 = new Parent();
parent1.name = "渋谷太郎";
// 子1の追加
Child child1_1 = new Child();
child1_1.name = "渋谷小太郎";
parent1.children.add(child1_1);
// 子2の追加
Child child1_2 = new Child();
child1_2.name = "渋谷小二郎";
parent1.children.add(child1_2);
// 親1の保存
parent1.save();
// 親2の作成
Parent parent2 = new Parent();
parent2.name = "恵比寿太郎";
// 子1の追加
Child child2_1 = new Child();
child2_1.name = "恵比寿小太郎";
parent2.children.add(child2_1);
// 子2の追加
Child child2_2 = new Child();
child2_2.name = "恵比寿小二郎";
parent2.children.add(child2_2);
// 親2の保存
parent2.save();
// 現在のParentを全検索して表示
Finder<Long, Parent> finder = new Finder<Long, Parent>(Long.class,
Parent.class);
List<Parent> parents = finder.all();
StringBuilder msg = new StringBuilder();
for (Parent parent : parents) {
msg.append(parent.toString()).append("\n");
// Child の表示
for (Child child : parent.children){
msg.append(" ").append(child.toString()).append("\n");
}
}
return ok(msg.toString());
}
}
再び「http://localhost:9000」にアクセスすると、Parentおよび関連するChildが保存されて、以下の結果が画面に表示されます。
ここからは、トランザクション制御について解説します。EBeanでは、デフォルトの状態で通常の操作を行ってもトランザクション制御が行われません。例えば、下記のコードがあるとします。
// Childを1つ削除
parent1.children.get(0).delete();
// 新規のChildを追加
Child child1_3 = new Child();
child1_3.name = “渋谷 小三郎”;
parent1.children.add(child1_3);
// 保存
parent1.save();
ここでparent1が持つChildを削除した後、すぐに(parent1が保存される前に)エラーが発生して処理を抜けた場合、そのChildは削除されたままになってしまいます。しかし、エラーが発生した場合は削除されずに実行前のままであってほしい場合がよくあります。そのような場合は最後まで処理が実行されて初めてDBへ反映(コミット)するようにトランザクションを使います。
まず、EBeanではトランザクションを扱うクラスとして「TxRunnable」が用意されています。これをEBean#execute()メソッドで呼び出します。
Parentが持つ全Childを削除した後に例外が発生した場合、Childが削除されていないか試してみましょう。下記のようにindex()メソッドを書き換えてください。
public static Result index() {
try {
// トランザクションの実行
Ebean.execute(new TxRunnable() {
@Override
public void run() {
// 現在の全検索
Finder<Long, Parent> finder = new Finder<Long, Parent>(
Long.class, Parent.class);
List<Parent> parents = finder.all();
// 現在登録されている子をすべて削除します。
for (Parent parent : parents) {
for (Child child : parent.children) {
child.delete();
}
}
// 例外を発生させる。
throw new RuntimeException();
}
});
} catch (Exception e) {
e.printStackTrace();
}
// 現在のParentとChildを全検索し表示する
……略……
}
再びWebブラウザを更新してください。前回と同じ画面が表示されChildが削除されていないことが確認できます。ちなみに上記ソースの例外を発生させている個所を削除して、再度実行すると、今度は問題なくChildが削除されていることが確認できます。
このように、EBean経由で基本的に使われるDB操作を紹介しました。このほかにも、EBeanではSQLを直接実行する機能など、ほかの機能も用意されています。また今回紹介した方法とは別の方法で同じこともできます。どの方法がベストかは場合によりけりです。詳細について知りたい方はEBeanのサイトなどでご確認ください。
最後に、実際によく使われるH2からほかのDBへの接続を紹介します。今回は、PostgreSQLに接続してみます。
まず、PostgreSQLに接続するDBを作成してください。DBのインストールおよび作成方法は、ここでは割愛します。PostgreSQLのサイトなどでご確認ください。
※ DBの文字コードがUTF-8になっているか確認してください。ちなみに、Windows版のPostgreSQL 9.1ではデフォルトでUTF-8になっています。PostgreSQLの文字コードの確認方法や変更方法はPostgreSQLのサイトなどでご確認ください。
プロジェクトを作成したディレクトリで「lib」フォルダを作成し、そこにJDBCドライバを置いてください。Playでは、すでにプロジェクト直下のlibフォルダにクラスパスが通っているので、Jarファイルを配置するたびにクラスパスを設定する必要はありません。
※ 逆に、クラスパスが通っていない場所にJarファイルを置いてもJarファイルを認識してくれません。
application.confを開き、PostgreSQLにアクセスできるように下記のよう書き換えてください。
db.default.driver=org.postgresql.Driver
db.default.url="jdbc:postgresql://localhost:5432/DB名"
db.default.user={ユーザー名}
db.default.password={パスワード}
Playが起動中の場合は、Playを再起動してください。Windowsのコマンドプロンプト上の場合、下記の手順で再起動できます。
※ まだ、起動していない場合は起動するだけで問題ありません。
再びWebブラウザにて確認してみましょう。今回はParentテーブルとChildテーブルにレコードが登録されることを確認できるようにApplication.javaのindex()メソッドを下記のように修正してください。
package controllers;
import ……略……
public class Application extends Controller {
public static Result index() {
// 親1の作成
Parent parent1 = new Parent();
parent1.name = "目黒太郎";
// 子1の追加
Child child1_1 = new Child();
child1_1.name = "目黒小太郎";
parent1.children.add(child1_1);
// 子2の追加
Child child1_2 = new Child();
child1_2.name = "目黒小二郎";
parent1.children.add(child1_2);
// 親1の保存
parent1.save();
// 現在のParentとChildを全検索して表示
……略……
}
}
次にWebブラウザより「http://localhost:9000」にアクセスしてください。DBテーブル作成のEvolutionのページが表示されます。画面上の「Apply this script now!」をクリックすると、PostgreSQLにH2で使っていたDBテーブルが作成され、プログラムで実行したデータが登録されます。
PostgreSQLのDBにアクセスして画面上に表示された内容がDBに登録されているか確認してください。画面と同じ内容が登録されているはずです。
今回はJava側のコードで直接SQLを扱っていないので、DB変更の対応は、これだけです。
※ application.confでは、DB接続以外にもいろいろな設定(autocommitやconnectionTimeoutなど)が用意されています。詳細はPlay frameworkのサイトを参照してください。
今回はPlay frameworkのDB周りの機能を一通り紹介してきました。まだまだ紹介しきれていない機能(「Database Evolutions」など)もありますが、取りあえず手軽にDB周りの処理が行えるようになったかと思います。
次回はPlay frameworkのビュー周りの機能を紹介しますので、お楽しみに。
長谷川 智之(はせがわ ともゆき)
2008年より、株式会社ビーブレイクシステムズに在籍。
基本的にはどんな問題があるか分からない新しい技術より、問題点をクリアした使い慣れた技術の方を好む保守派。しかし、最近のヤングでナウな新世代の考えに乗り遅れてきたため、新しい技術にも手を出し始める。
Copyright © ITmedia, Inc. All Rights Reserved.