2014年5月16日金曜日

JPAを使ってみる。なるべく単純に。

JPAを試してみたい。Java SEで、Eclipse IDE for Java EE DevelopersとApache Derbyで、ひとまずエンティティの保存と取得まで。


まず、DBとしてApache Derbyを用意する。ダウンロード、展開の上、bin内のstartNetworkServer.batで起動しておく。


EclipseはEE版を利用する。これなら、新規プロジェクト作成時点で「JPA Project」なるものが選べる。

プロジェクト作成時のダイアログで、実装を選ぶことになるがここでEclipseLinkを選択かつダウンロードする。

できたプロジェクトのビルドパスに、derby.jarとderbyclient.jarを追加しておく。


Eclipseのプロジェクト内にJPA Contentなるものがあり、そこにpersistence.xmlというファイルが用意されている。

persistence-unit要素の中身がないので、書いてやる。



実際にはわりと紆余曲折あったのだが、とりあえずこうなった。


<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="myUnit" transaction-type="RESOURCE_LOCAL">
<class>mypackage.MyEntity</class>
<properties>
<property name="javax.persistence.schema-generation.create-database-schemas" value="true"/>
<property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.ClientDriver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:derby://localhost/c:/D/Derby/MyData/JPA-TEST;create=true"/>
<property name="javax.persistence.jdbc.user" value="app"/>
<property name="javax.persistence.jdbc.password" value="app"/>
<property name="javax.persistence.schema-generation.database.action" value="create"/>
</properties>

</persistence-unit>
</persistence>


実際には、JPAプロジェクトでpersisntence.xmlをダブルクリックして表示されるエディタのダイアログに適当なことを入力して生成したもの。

スキーマ自動生成のオプションがちょっとわかりにくい。のと、createを選択していても、一度生成済みなら生成しない(当然だが)ので、テストコードがIDの生成で失敗した後にIDの型を変えたら、今度はDBの方で型の不一致が起こった。で、drop & createでやり直したらうまくいった。


作ったエンティティというかモデルクラスというかは、これ。


package mypackage;
import java.util.UUID;
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class MyEntity {
@Id
private String id = UUID.randomUUID().toString();
private String name;
private String description;

public void update(String name, String description){
this.name = name;
this.description = description;
}
public String id(){
return this.id;
}
public String toString(){
return String.format("%s(%s) : %s", name, id, description);
}
}


IDはひとまずサンプルにありがちなlongの連番にでもしようとして

 @ID
 @GeneratedValue(strategy=GenerationType.SEQUNCE)
 private Long id;

とかやったら、何かシーケンス生成でコケてた。調べるが面倒だし実はシーケンスのIDが好きでもないので、ランダム文字列を生成してみた。


このエンティティを新規に永続化・・・つうかDBに登録し、再度取り出すコードがこれ。

package mypackage;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
public class Main {
public static void main(String[] a){
String id;
{
EntityManagerFactory f = Persistence.createEntityManagerFactory("myUnit");
EntityManager em = f.createEntityManager();
EntityTransaction tx = em.getTransaction();
MyEntity foo = new MyEntity();
id = foo.id();
foo.update("Foo", "hogehoge");
tx.begin();
em.persist(foo);
tx.commit();
em.close();
f.close();
}
{
EntityManagerFactory f = Persistence.createEntityManagerFactory("myUnit");
EntityManager em = f.createEntityManager();
MyEntity foo = em.find(MyEntity.class, id);
System.out.println(foo);
}
}
}


効率的なことやエラーハンドリング的なことはさておき、単純にした。

これで、実行結果は、

Foo(f2f37087-2919-4579-825d-4624f9711f0d) : hogehoge

実際、Derbyにijで接続して中身を見ると、MYENTITYという名前(クラス名を大文字にしたもののようだ)のテーブルが勝手に生成されており、上記のデータが1件入っていた。


JPQLの使い方はこれからだが、たとえそれをまったく使わなくて検索部分は普通にJDBCを使ったとしても、上記のようなエンティティの登録と取得が自動になれば楽には楽だろうと思える。とは言え、JPQLは悪くなさそうなので使ってみるつもりではある。クリテリアAPIは煩雑そうで、試してみる気力もわかない。メタモデルだったっけか?とかも。

persistence.xmlをいちいち書かなくてはいけないのだろうか。それが何とも面倒くさい。複雑なシステムであればそういった管理の必然性もあるだろうが、簡単なケースのためになんかもっとこう端折ってデフォルトの動作ならエンティティ別の記述はいらないとかないのだろうか?



補遺

しくじったときのスタックトレースから。

Internal Exception: java.sql.SQLSyntaxErrorException: スキーマ'ME'は存在しません
Error Code: 20000
Call: INSERT INTO MYENTITY (ID, DESCRIPTION, NAME) VALUES (?, ?, ?)
bind => [3 parameters bound]
Query: InsertObjectQuery(Foo : hogehoge)

当たり前だがこんな感じでSQLが自動生成されるわけで。わかっちゃいるけど、まあ納得という感じだ。


参考になった記事

なんとなく全体像:http://yoshio3.com/2011/12/19/java-persistence-api-for-begineers/
 とりわけ、このスライド:http://www.slideshare.net/OracleMiddleJP/the-detail-of-jpa-20
EclipseLink関連部分:http://www.vogella.com/tutorials/JavaPersistenceAPI/article.html

1 件のコメント:

  1. Eclipse だからめんどくさいんだと思います。(^_^;)
    NetBeans ならばもっと簡単にかけます。

    返信削除