2009/12/01
GAE/JのJDOのトランザクション
JDOの(と言うかGAE固有かもしれない)トランザクションは結構ややこしい。
まず一旦、従来のRDBは忘れた方が良い。
GAEの場合、前提条件として
親から子への参照はフツー、子から親への逆参照は専用のアノテーションが必要。
丸1日はまって分かったのが「PersistenceManagerを閉じたらダメ」と言うこと。 理屈は分からんでも無い。 しかし、DBを隠蔽しているのにここで突然DB依存の話を出されても訳分からん。 それに「元々null値を持っていた」のと「取得できなかった」の区別が付かない。 何で例外を上げないのか? 仕様なら仕様バグだろ。 で最終的にこうなった。
- DBは複数のサーバに分散している。
- だけど、分散トランザクションはしたくない。
- 1つの エンティティ グループ は1つのDBに保存し
- 複数の エンティティ グループ は同一トランザクションに入れない。
親 | 子 | |
---|---|---|
@PersistenceCapable(identityType = IdentityType.APPLICATION) public class PageInfoJDO { @PrimaryKey @Persistent private String pageName; @Persistent private PageBodyJDO pageBodyJDO; : | => |
@PersistenceCapable(identityType = IdentityType.APPLICATION) public class PageBodyJDO { @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) private Key key; @Persistent(mappedBy = "pageBodyJDO") private PageInfoJDO pageInfo; @Persistent private Blob body; : |
@Persistent(mappedBy = "子を参照している親のフィールド名")子の主キーは com.google.appengine.api.datastore.Key型必須でアノテーションを
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)として自動設定にして置く。 手動設定はまたややこしいのでグーグルのドキュメントを参照。 後は普通に makePersistent() で親を保存すると子も一緒に保存される。
public static void putPageInfo(PageInfoJDO info) { PersistenceManager pm = getPMF().getPersistenceManager(); Transaction tx = pm.currentTransaction(); tx.begin(); try { pm.makePersistent(info); tx.commit(); } finally { if (tx.isActive()) tx.rollback(); pm.close(); } }で、はまったのはここから。 ドキュメント通りに親を取得して子にアクセスしたら NullPointer。
PageInfoJDO info = getPageInfo(pageName); byte[] buff = info.getBody().getBytes(); <-- NullPointer public static PageInfoJDO getPageInfo(String pageName) { PersistenceManager pm = getPMF().getPersistenceManager(); try { List<PageInfoJDO> sel = (List<PageInfoJDO>) pm.newQuery(PageInfoJDO.class, "pageName=='"+pageName+"'").execute(); if (sel.size() == 0) return null; PageInfoJDO info = sel.get(0); return info; } finally { pm.close(); } }ドキュメントには子にアクセスすれば自動的にDBから取得してくる となっているのに..
丸1日はまって分かったのが「PersistenceManagerを閉じたらダメ」と言うこと。 理屈は分からんでも無い。 しかし、DBを隠蔽しているのにここで突然DB依存の話を出されても訳分からん。 それに「元々null値を持っていた」のと「取得できなかった」の区別が付かない。 何で例外を上げないのか? 仕様なら仕様バグだろ。 で最終的にこうなった。
public static PageInfoJDO getPageInfo(String pageName, boolean withBody) { PersistenceManager pm = getPMF().getPersistenceManager(); try { List sel = (List) pm.newQuery(PageInfoJDO.class, "pageName=='"+pageName+"'").execute(); if (sel.size() == 0) return null; PageInfoJDO info = sel.get(0); if (withBody) info.getBody().getBytes(); return info; } finally { pm.close(); } }Body が必要な時はトランザクションの中で取得してから返す様にした。 一回取得するとpm.close()後でも取得できる。 因みに Blob 型は別オブジェクトとなるようで getBytes() して置かないと Blob の中身が空っぽになる。 Blob が別オブジェクトになる事が分かったので PageBodyJDO は廃止して 昨日の記事の状態となった。 GAE/J は枯れて無いのでまだまだ人柱が必要だね.. orz
追記:2010.02.04
@Persistent(defaultFetchGroup = "true")
とすれば自動で取得してくれそう。
でもBlobは不要な時も有るよね..
Error: Server Error The server encountered an error and could not complete your request. If the problem persists, please report your problem and mention this error message and the query that caused it.ログも見れずこれでどうしろと? ここは一つ戦略的撤退と言うことで...
この投稿へのコメント

コメント・フォーム