JDO
JDOは、データベースから独立してデータの永続化操作を行うための処理を定義した仕様で、RDBMSやオブジェクトデータベース、XMLなどさまざまな種類のデータストアに対応しています。
Google App Engine for JavaではJDO 2.3に対応しており、DataNucleus Access Platform 1.1を基にした実装ライブラリを含んでいます。
JDOでは、POJO(Plain Old Java Object)に対して、永続化対象となるクラスやフィールドにアノテーションを記述することで、どのようなデータを永続化させるのかという定義を行います。アノテーション定義を行ったJavaクラスは、App Engineデータストアではエンティティ(Entity)として扱われます。エンティティは1つ以上のプロパティ(Property)を持ちます。
アノテーションで定義したクラスは通常のコンパイル後に「Enhancement」と呼ばれる後処理を実行することでJDOとの関連づけを行います。Google Plugin for Eclipseではこの処理は自動的に実行されます。
Javaのソースをコンパイルすると、次のようにコンソールにEnhancementの結果が表示されます。
JDOによる永続化の指定
それではどのようにJavaクラス(POJO)に対して永続化の情報を定義するかを見ていきましょう。
ここではコンタクト情報を管理するクラスを永続化対象とするコードを例にとります。
package sample; // (1)永続化対象クラスの定義 @PersistenceCapable(identityType = IdentityType.APPLICATION) public class ContactInfo { // (2)主キーとなる永続化対象フィールドの定義 @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) private Long id; // (3)永続化対象フィールドの定義 @Persistent private String firstName; // (3)永続化対象フィールドの定義 @Persistent private String lastName; // (3)永続化対象フィールドの定義 @Persistent private String email; public ContactInfo(String firstName, String lastName, String email) { this.firstName = firstName; this.lastName = lastName; this.email = email; } // getter/setter }
(1)永続化対象クラスの定義
永続化対象クラスに対して@PersistenceCapableアノテーションを宣言します。
(2)主キーとなる永続化対象フィールドの定義
主キーとなる永続化対象フィールドに対して@PrimaryKeyアノテーションを宣言しますす。一つのクラスに必ず一つは主キーとなるフィールドを定義しなければなりません(埋め込みクラスをのぞく)。
永続化対象フィールドに対して@Persistentアノテーションを宣言しますが、主キーで値を自動生成する場合には、この例のようにvalueStrategyに対してIdGeneratorStrategyのEnum値を設定する必要があります。
(3)永続化対象フィールドの定義
永続化対象フィールドに対して@Persistentアノテーションを宣言します。
@Persistentアノテーションを定義できるフィールドの型は次のようなものがあります。
- App EngineデータストアでサポートされたCore type
- java.util.List<...>のようなCollectionまたはCore typeの配列
- @PersistenceCapable宣言されたクラスのインスタンスや、このインスタンスのCollection
- Serializableなクラスのインスタンスや、このインスタンスのCollection
- エンティティでプロパティとして永続化されるように定義されている埋め込みクラス
Core typeには次のようなものがあります。
- java.lang.String
- boolean/java.lang.Boolean
- short/java.lang.Short
- int/java.lang.Integer
- long/java.lang.Long
- float/java.lang.Float
- double/java.lang.Double
- java.util.Date
- com.google.appengine.api.datastore.ShortBlob
- com.google.appengine.api.datastore.Text
- com.google.appengine.api.datastore.Blob
- com.google.appengine.api.datastore.Key
- com.google.appengine.api.users.User
- com.google.appengine.api.datastore.Link
また、主キーとなるフィールドにはメールアドレスなどの値を設定することもできます。
永続化対象クラスの操作に必要なクラス
アノテーションで永続化対象としたクラスをApp Engineデータストアとやりとりするには、PersistenceManager
クラスを使用します。
PersistenceManager
クラスのインスタンスは、次のように取得するのが一般的です。
PersistenceManager pm = PMF.get().getPersistenceManager();
ここで出てくるPMFというクラスは、PersistenceManagerFactory
クラス(PersistenceManagerのファクトリクラス)のインスタンスを管理するユーティリティクラスです。Google App Engine for Javaのドキュメントにもよく出てきます。
import javax.jdo.JDOHelper; import javax.jdo.PersistenceManagerFactory; public final class PMF { // (1)jdoconfig.xmlのpersistence-manager-factory/@nameの値を指定 private static final PersistenceManagerFactory pmfInstance = JDOHelper.getPersistenceManagerFactory("transactions-optional"); private PMF() {} public static PersistenceManagerFactory get() { return pmfInstance; } }
(1)の処理でJDOHelper
クラスのgetPersistenceManagerFactory
メソッドに渡している「transactions-optional」という文字列はJDOの設定名を表しています。この名前は「src/META-INF/jdoconfig.xml」で定義されるJDOの設定情報と一致させる必要があります。
このjdoconfig.xmlファイルは、Google Plugin for Eclipseでプロジェクトを作成するとツールにより「src/META-INF」以下に生成され、ビルド時に「war/WEB-INF/classes/META-INF」以下に配置されます。
永続化対象クラスの保存、更新、削除、検索
先ほどのContactInfo
クラスを例に、保存、更新、削除、検索の処理を見ていきましょう。
ContactInfo
クラスのインスタンスを保存するには、PersistenceManager
クラスのmakePersistent()
メソッドを使用します。
PersistenceManager
クラスのインスタンスは、使い終わったら必ずclose()
メソッドを呼び出す必要があります。
PersistenceManager pm = PMF.get().getPersistenceManager(); ContactInfo c = new ContactInfo("Alfred", "Smith", "Alfred@example.com"); try { pm.makePersistent(c); } finally { pm.close(); }
次にemailの値を更新する例を見ていきます。取得したContactInfo
クラスのインスタンスに対してsetEmail()
メソッドで新しい値を設定し、PersistenceManager
クラスのmakePersistent()
メソッドに渡します。
PersistenceManager pm = PMF.get().getPersistenceManager(); ContactInfo c = ... // 取得 c.setEmail("Alfred.Smith@example.com"); try { pm.makePersistent(c); } finally { pm.close(); }
削除する場合には、PersistenceManager
クラスのdeletePersistent()
メソッドを使用します。
PersistenceManager pm = PMF.get().getPersistenceManager(); ContactInfo c = ... // 取得 try { pm.deletePersistent(c); } finally { pm.close(); }
検索では、JDOQLというSQLに似た言語が使用できます。次の例では、lastNameが"Smith"に一致するContactInfo
クラスのインスタンスを取得しています。
PersistenceManager pm = PMF.get().getPersistenceManager(); try { Query query = pm.newQuery("select from sample.ContactInfo " + "where lastName == lastNameParam " + "parameters String lastNameParam"); List<ContactInfo> results = (List<ContactInfo>) query.execute("Smith"); } finally { pm.close(); }
検索結果はjava.util.List<ContactInfo>
として返されます。
クエリ文のfromの後には検索対象となるクラスのFQCN(Fully Qualified Class Name)を指定します。
この例ではクエリ文で"lastNameParam"というパラメータを定義し、Query
クラスのexecute()
メソッドに"lastNameParam"パラメータの値を渡しています。
Query
クラスではパラメータや他の条件を別メソッドで渡すことができますが、次のように1行ですべてを記述することもできます。
PersistenceManager pm = PMF.get().getPersistenceManager(); try { Query query = pm.newQuery("select from sample.ContactInfo " + "where lastName == 'Smith'"); List<ContactInfo> results = (List<ContactInfo>) query.execute(); } finally { pm.close(); }