App Engine for Java の JDO
使用上の考慮点

   (株)ケーピーエス 平 克介
目次
   RDB から JDO への実装の変更概要
       今回トライした例について
   JDO の基本
   考慮点 –  Transaction
   考慮点 – 関連
   考慮点 –  PersistenceMan...
KPS フレームワークの機能
    クライアントから直接擬似 HibernateAPI を操作
        ORM オブジェクトを検索、更新、作成、削除
    クライアントからサーバー側 Sesar2 コンポーネン
     トの...
JDO への移行
   サーバー側の ORM アクセス部分の変更
       Hibernate から JDO へ
           フレームワーク側の変更
   クライアント側検索 API の変更
       Criteri...
JDO の基本1
   JDO とは
       Java 標準のデータの永続化・検索機能を提供す
        る API
   JDO の ORM クラス( GAE では kind と呼
    ぶ)
    @Persisten...
JDO の基本 2

   Object(entity) を永続化する


       PersistenceManager pm = PMF.get().getPersistenceManager();
       Employee e...
JDO の基本 3
   Object の更新
     PersistenceManager pm = PMF.get().getPersistenceManager();
     try {
         Employee e = ...
JDO の基本 4
   Object の検索
    Query query = pm.newQuery(Employee.class);
    query.setFilter("lastName == lastNameParam");
...
JDO の基本 5
    Transaction
    Transaction tx = pm.currentTransaction();
    try {
        tx.begin();
        ClubMembers...
JDO の基本 6
   com.google.appengine.api.datastore.Key
    import com.google.appengine.api.datastore.Key;
    // ...
       ...
JDO の基本 7
   関連
       Employee.java
    // ...
        @Persistent(mappedBy = "employee")
        private List<ContactI...
参考資料
   ORM クラス間の一般的な関連の実装方法
                       RDB の場合:主キー / 外部キーの関連
     商品テーブル
                                   ...
考慮点 (Transaction)
   1 Transaction 内では同一の entity group に
    属する entity しか扱えない
           tx.begin();
         Query quer...
考慮点 (Transaction)
   Transaction の制約を受けない方法
       単一の entity 「 root 」をすべての親の無い entity
        の親にする


                 ...
考慮点 (Transaction)
   Root クラス ( 主キーだけあればよい )
    @PersistenceCapable(identityType = IdentityType.APPLICATION)
    public ...
考慮点 (Transaction)
   親の無い entity の例( Root の Key を持たせる )
 @PersistenceCapable(identityType = IdentityType.APPLICATION)
pub...
考慮点 (Transaction)
   親が root である Entity の新規作成
       root の key をセットする (root のキー値が1の場
        合)
    // ...
    Employee...
考慮点 ( 関連 )
    関連実装時の問題(関連が Key の構造にな
     る)
         親を一度設定すると変更できない
         複数の親を定義できない
  division1          divisi...
考慮点 7 ( 関連 - 解決策 )
     関連は親の Key を保持することで実装する
@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class ...
考慮点 (PersistenceManager)
   PersistenceManager の使いまわし
       一連の処理で使用する PersistenceManager は同
        一のものを使用する必要がある。
  ...
考慮点 (PersistenceManager)
   PersistenceManager を request に保持する
      public class PMManager {
      public static final S...
考慮点 (PersistenceManager)
   PMManager から入手する例

     // ...
      Season s = question.getSeason();
      s.setCnt(s.getCnt...
考慮点 (Index)
   検索条件によっては明示的に Index を定義す
    る必要がある。
       Google の資料で Index 定義が必要な検索とは
           複数のソートが指定された場合
     ...
考慮点 (Index)
   Index の設定例
       war/WEB-INF/datastore-indexes.xml に指定

        <?xml version="1.0" encoding="utf-8"?>
 ...
その他の考慮点

   kind 間の Join による読み込みはできない
   group by を使用した集約関数は使用できない
       count(*) / sum(xxx) 等
   検索条件に  != 、 IN は使用で...
おわり

   ありがとうございました
Upcoming SlideShare
Loading in …5
×

Gaej Jdo

3,152 views

Published on

Published in: Technology
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
3,152
On SlideShare
0
From Embeds
0
Number of Embeds
789
Actions
Shares
0
Downloads
24
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

Gaej Jdo

  1. 1. App Engine for Java の JDO 使用上の考慮点 (株)ケーピーエス 平 克介
  2. 2. 目次  RDB から JDO への実装の変更概要  今回トライした例について  JDO の基本  考慮点 –  Transaction  考慮点 – 関連  考慮点 –  PersistenceManager  考慮点 –  Index  参考:基本情報技術者試験 午前問題特訓システム
  3. 3. KPS フレームワークの機能  クライアントから直接擬似 HibernateAPI を操作  ORM オブジェクトを検索、更新、作成、削除  クライアントからサーバー側 Sesar2 コンポーネン トの呼び出し  Gxt   GUI 画面デザインツール  D-RexGxt Hibernate 部分を JDO へ入れ替え Criteria を Query 集計処理部分の  へ変更 変更
  4. 4. JDO への移行  サーバー側の ORM アクセス部分の変更  Hibernate から JDO へ  フレームワーク側の変更  クライアント側検索 API の変更  Criteria から Query へ  フレームワークおよびクライアントコードの変更  集計処理部分の変更  集計処理を行っている Seaser2 コンポーネントの 変更
  5. 5. JDO の基本1  JDO とは  Java 標準のデータの永続化・検索機能を提供す る API  JDO の ORM クラス( GAE では kind と呼 ぶ) @PersistenceCapable(identityType = IdentityType.APPLICATION) public class Employee { @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) private Long id; @Persistent private String firstName; @Persistent private String lastName; この下に constructor : getter/setter が続く
  6. 6. JDO の基本 2  Object(entity) を永続化する PersistenceManager pm = PMF.get().getPersistenceManager(); Employee e = new Employee("Alfred", "Smith", new Date()); try { pm.makePersistent(e); } finally { pm.close(); } :
  7. 7. JDO の基本 3  Object の更新 PersistenceManager pm = PMF.get().getPersistenceManager(); try { Employee e = pm.getObjectById(Employee.class, 1); e.setTitle(newTitle); } finally { pm.close(); } :  Object の削除 pm.deletePersistent(e);        :
  8. 8. JDO の基本 4  Object の検索 Query query = pm.newQuery(Employee.class); query.setFilter("lastName == lastNameParam"); query.setOrdering("hireDate desc"); query.declareParameters("String lastNameParam"); try { List<Employee> results = (List<Employee>) query.execute("Smith"); if (results.iterator().hasNext()) { for (Employee e : results) { // ... } } else { // ... no results ... Where lastName=‘Smith’ } Order by hireDate desc } finally { に相当 query.closeAll(); } :
  9. 9. JDO の基本 5  Transaction Transaction tx = pm.currentTransaction(); try { tx.begin(); ClubMembers members = pm.getObjectById(ClubMembers.class, "k12345"); members.incrementCounterBy(1); pm.makePersistent(members); tx.commit(); } finally { if (tx.isActive()) { Tx 間に他所で同じ entity が更新された場 tx.rollback(); 合 } JDOOptimisticVerificationException とな } る :
  10. 10. JDO の基本 6  com.google.appengine.api.datastore.Key import com.google.appengine.api.datastore.Key; // ... @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) private Key key; public void setKey(Key key) { this.key = key; } :  親のクラスを持つ場合は主キーに Key を使用する  Key は親のクラスの Key への参照を持つ  子 Key→ 親 Key  Entity の Key は変更できない
  11. 11. JDO の基本 7  関連  Employee.java // ... @Persistent(mappedBy = "employee") private List<ContactInfo> contactInfoSets;  ContactInfo.java // ... @Persistent private Employee employee;  Employee:Contactinfo = 1:N  この場合 Employee が Contactinfo の親になる  共通の親(親の親も含む)を持つ entity の集合を entity group と言う
  12. 12. 参考資料  ORM クラス間の一般的な関連の実装方法 RDB の場合:主キー / 外部キーの関連 商品テーブル 外部キ 商品 CD 商品名 単価 商品メーカー CDー 商品メーカーテーブル 商品メーカー CD 商品メーカー名 関連相手の Object 主キー の参照を持つ 関連相手の Object の集合の参照を持つ ORM でのオブジェクト間の関連 Shohin ShohinMaker 1 String shohinCd 0..* String shohinMakerCd String shohinNm String shohinMakerNm Long tanka Set shohins ShohinMaker shohinMaker getShohinMaker() getShohins()
  13. 13. 考慮点 (Transaction)  1 Transaction 内では同一の entity group に 属する entity しか扱えない    tx.begin(); Query query = pm.newQuery(Employee.class); List<Employee> results = (List<Employee>) query.execute(); Employee e1 = results.get(0); Employee e2 = results.get(1); e1.setFirstName(e1.getFirstName() + "1"); e2.setFirstName(e2.getFirstName() + "2"); tx.commit(); javax.jdo.JDOException  つまり、共通の親を持つ entity しか Transaction 化できない
  14. 14. 考慮点 (Transaction)  Transaction の制約を受けない方法  単一の entity 「 root 」をすべての親の無い entity の親にする root employee1 employee2 employee3 company1 company2 contactInfo1 contactInfo2 すべては同一の entity group
  15. 15. 考慮点 (Transaction)  Root クラス ( 主キーだけあればよい ) @PersistenceCapable(identityType = IdentityType.APPLICATION) public class Root { @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) private Key key; public Key getKey() { return key; } public void setKey(Key key) { this.key = key; } }
  16. 16. 考慮点 (Transaction)  親の無い entity の例( Root の Key を持たせる ) @PersistenceCapable(identityType = IdentityType.APPLICATION) public class Employee { @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) private Key key; @Persistent @Extension(vendorName="datanucleus", key="gae.parent-pk", value="true") private Key rootKey; public void setRootKey(Key rootKey) { this.rootKey = rootKey; } }  Root との ManyToOne 関連を持たせる方法でも OK
  17. 17. 考慮点 (Transaction)  親が root である Entity の新規作成  root の key をセットする (root のキー値が1の場 合) // ... Employee e = new Employee("Alfred", "Smith", new Date()); Key key = KeyFactory.createKey("Root", 1); e.setRootKey(key); pm.makePersistent(e); :
  18. 18. 考慮点 ( 関連 )  関連実装時の問題(関連が Key の構造にな る)  親を一度設定すると変更できない  複数の親を定義できない division1 division2 2009 年春の「コンピュータの基礎」の問題 season1 genre1 x employee1 x Employee1 は一生 division1 question1 Season と Genre 両方親に出来ない
  19. 19. 考慮点 7 ( 関連 - 解決策 )  関連は親の Key を保持することで実装する @PersistenceCapable(identityType = IdentityType.APPLICATION) public class Question { @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) private Key key; @Persistent private Key seasonKey; @Persistent 関連先 Object を要求された時 private Key genreKey; に entity を読む public Season getSeason() { if (this.seasonKey == null) { return null; } return getPm().getObjectById(Season.class, this.seasonKey); } public void setSeason(Season season) { this.seasonKey = season.getKey(); } :
  20. 20. 考慮点 (PersistenceManager)  PersistenceManager の使いまわし  一連の処理で使用する PersistenceManager は同 一のものを使用する必要がある。 // ... Season s = question.getSeason(); s.setCnt(s.getCnt()+1); pm.makePersistent(s); public Season getSeason() { if (this.seasonKey == null) { return null; } return pm.getObjectById(Season.class, this.seasonKey); }
  21. 21. 考慮点 (PersistenceManager)  PersistenceManager を request に保持する public class PMManager { public static final String pmName = " PMManager _PM"; public static PersistenceManager getPm() { HttpServletRequest request = null; PersistenceManager pm = null; try { request = (HttpServletRequest) SingletonS2ContainerFactory .getContainer().getComponent(HttpServletRequest.class); pm = (PersistenceManager) request.getAttribute(pmName); } catch (Exception e) { } if (pm == null) { pm = PMF.get().getPersistenceManager(); if (request != null) { request.setAttribute(pmName, pm); この場合 Seasar2 のコンテナ } から request を得ている } return pm; } }
  22. 22. 考慮点 (PersistenceManager)  PMManager から入手する例 // ... Season s = question.getSeason(); s.setCnt(s.getCnt()+1); PMManager.getPm().makePersistent(s); public Season getSeason() { if (this.seasonKey == null) { return null; } return PMManager.getPm() . getObjectById(Season.class, this.seasonKey); }
  23. 23. 考慮点 (Index)  検索条件によっては明示的に Index を定義す る必要がある。  Google の資料で Index 定義が必要な検索とは  複数のソートが指定された場合  Key の逆順ソートの場合  == でない条件と == の条件がある場合  == の条件と ancestor フィルターがある場合  Local 環境で OK でも Deploy した環境で NG の場 合がある
  24. 24. 考慮点 (Index)  Index の設定例  war/WEB-INF/datastore-indexes.xml に指定 <?xml version="1.0" encoding="utf-8"?> <datastore-indexes autoGenerate="false"> <datastore-index kind="Question" ancestor="false" source="auto"> <property name="seasonKey" direction="asc"/> <property name="genreKey" direction="asc"/> </datastore-index> </datastore-indexes>
  25. 25. その他の考慮点  kind 間の Join による読み込みはできない  group by を使用した集約関数は使用できない  count(*) / sum(xxx) 等  検索条件に  != 、 IN は使用できない  Python ではクライアント側の実装として実現し ている  検索条件の組み合わせで or 、 not は使用で きない
  26. 26. おわり  ありがとうございました

×